@scotthamilton77/sidekick 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/assets/sidekick/defaults/README.md +2 -17
  2. package/assets/sidekick/defaults/core.defaults.yaml +1 -1
  3. package/assets/sidekick/defaults/features/session-summary.defaults.yaml +21 -0
  4. package/assets/sidekick/defaults/llm.defaults.yaml +5 -1
  5. package/assets/sidekick/personas/avasarala.yaml +13 -28
  6. package/assets/sidekick/personas/bones.yaml +25 -21
  7. package/assets/sidekick/personas/c3po.yaml +28 -21
  8. package/assets/sidekick/personas/captain-kirk.yaml +26 -24
  9. package/assets/sidekick/personas/cavil.yaml +14 -15
  10. package/assets/sidekick/personas/darth-vader.yaml +27 -19
  11. package/assets/sidekick/personas/dilbert.yaml +25 -24
  12. package/assets/sidekick/personas/eddie.yaml +17 -18
  13. package/assets/sidekick/personas/emh.yaml +34 -31
  14. package/assets/sidekick/personas/{emperor.yaml → emperor-palpatine.yaml} +14 -14
  15. package/assets/sidekick/personas/george.yaml +32 -29
  16. package/assets/sidekick/personas/glados.yaml +8 -9
  17. package/assets/sidekick/personas/hudson.yaml +30 -20
  18. package/assets/sidekick/personas/jarvis.yaml +23 -22
  19. package/assets/sidekick/personas/kramer.yaml +34 -26
  20. package/assets/sidekick/personas/marvin.yaml +27 -26
  21. package/assets/sidekick/personas/mr-spock.yaml +23 -22
  22. package/assets/sidekick/personas/mr-t.yaml +24 -16
  23. package/assets/sidekick/personas/pointy-haired-boss.yaml +19 -15
  24. package/assets/sidekick/personas/ripley.yaml +35 -23
  25. package/assets/sidekick/personas/rodney-mckay.yaml +27 -28
  26. package/assets/sidekick/personas/scotty.yaml +23 -16
  27. package/assets/sidekick/personas/seven-of-nine.yaml +22 -24
  28. package/assets/sidekick/personas/sheldon.yaml +32 -22
  29. package/assets/sidekick/personas/skippy.yaml +28 -27
  30. package/assets/sidekick/personas/tars.yaml +18 -17
  31. package/assets/sidekick/personas/yoda.yaml +27 -18
  32. package/assets/sidekick/prompts/resume-message.prompt.txt +6 -0
  33. package/assets/sidekick/prompts/snarky-message.prompt.txt +6 -0
  34. package/assets/sidekick/reminders/user-profile.yaml +11 -0
  35. package/dist/bin.js +1094 -165
  36. package/dist/daemon.js +627 -131
  37. package/package.json +1 -1
package/dist/daemon.js CHANGED
@@ -16173,7 +16173,27 @@ var require_persona = __commonJS({
16173
16173
  /** Optional persona-specific snarky welcome examples for returning users (8-10 words max) */
16174
16174
  snarky_welcome_examples: zod_1.z.array(zod_1.z.string()).optional(),
16175
16175
  /** Optional situational context override (default: "You are watching over the shoulder of a software developer as they work.") */
16176
- situation: zod_1.z.string().optional()
16176
+ situation: zod_1.z.string().optional(),
16177
+ /** Optional recommended LLM profile for persona-driven outputs (snarky, resume) */
16178
+ llmProfile: zod_1.z.string().optional()
16179
+ });
16180
+ }
16181
+ });
16182
+
16183
+ // ../types/dist/services/user-profile.js
16184
+ var require_user_profile = __commonJS({
16185
+ "../types/dist/services/user-profile.js"(exports2) {
16186
+ "use strict";
16187
+ Object.defineProperty(exports2, "__esModule", { value: true });
16188
+ exports2.UserProfileSchema = void 0;
16189
+ var zod_1 = require_zod();
16190
+ exports2.UserProfileSchema = zod_1.z.object({
16191
+ /** User's display name */
16192
+ name: zod_1.z.string().min(1),
16193
+ /** User's role (e.g., "Software Architect") */
16194
+ role: zod_1.z.string().min(1),
16195
+ /** User's interests as string array */
16196
+ interests: zod_1.z.array(zod_1.z.string())
16177
16197
  });
16178
16198
  }
16179
16199
  });
@@ -16289,7 +16309,11 @@ var require_state = __commonJS({
16289
16309
  /** Snarky welcome message for returning user */
16290
16310
  snarky_comment: zod_1.z.string(),
16291
16311
  /** ISO8601 timestamp when this was generated */
16292
- timestamp: zod_1.z.string()
16312
+ timestamp: zod_1.z.string(),
16313
+ /** Persona ID that generated this message (null when persona disabled) */
16314
+ persona_id: zod_1.z.string().nullable().default(null),
16315
+ /** Display name for attribution (null when persona disabled) */
16316
+ persona_display_name: zod_1.z.string().nullable().default(null)
16293
16317
  });
16294
16318
  exports2.TranscriptMetricsStateSchema = zod_1.z.object({
16295
16319
  /** Session identifier */
@@ -16605,6 +16629,7 @@ var require_services = __commonJS({
16605
16629
  Object.defineProperty(exports2, "__esModule", { value: true });
16606
16630
  __exportStar(require_config(), exports2);
16607
16631
  __exportStar(require_persona(), exports2);
16632
+ __exportStar(require_user_profile(), exports2);
16608
16633
  __exportStar(require_service_factory(), exports2);
16609
16634
  __exportStar(require_staging(), exports2);
16610
16635
  __exportStar(require_state(), exports2);
@@ -26656,10 +26681,13 @@ var require_config2 = __commonJS({
26656
26681
  "../sidekick-core/dist/config.js"(exports2) {
26657
26682
  "use strict";
26658
26683
  Object.defineProperty(exports2, "__esModule", { value: true });
26659
- exports2.SidekickConfigSchema = exports2.FeaturesConfigSchema = exports2.TranscriptConfigSchema = exports2.LlmConfigSchema = exports2.CoreConfigSchema = void 0;
26684
+ exports2.EXTERNAL_DEFAULTS_FILES = exports2.SidekickConfigSchema = exports2.FeaturesConfigSchema = exports2.TranscriptConfigSchema = exports2.LlmConfigSchema = exports2.CoreConfigSchema = exports2.DOMAIN_FILES = void 0;
26685
+ exports2.deepMerge = deepMerge;
26686
+ exports2.coerceValue = coerceValue;
26687
+ exports2.setNestedValue = setNestedValue;
26688
+ exports2.tryReadYaml = tryReadYaml;
26660
26689
  exports2.loadConfig = loadConfig;
26661
26690
  exports2.createConfigService = createConfigService;
26662
- exports2.parseUnifiedConfig = parseUnifiedConfig;
26663
26691
  var dotenv_1 = require_main();
26664
26692
  var node_fs_1 = require("node:fs");
26665
26693
  var node_os_1 = require("node:os");
@@ -26679,8 +26707,8 @@ var require_config2 = __commonJS({
26679
26707
  }
26680
26708
  return obj;
26681
26709
  }
26682
- var DOMAIN_FILES = {
26683
- core: "config.yaml",
26710
+ exports2.DOMAIN_FILES = {
26711
+ core: "core.yaml",
26684
26712
  llm: "llm.yaml",
26685
26713
  transcript: "transcript.yaml",
26686
26714
  features: "features.yaml"
@@ -26734,14 +26762,17 @@ var require_config2 = __commonJS({
26734
26762
  maxTokens: v4_1.z.number().positive(),
26735
26763
  timeout: v4_1.z.number().min(1).max(300),
26736
26764
  timeoutMaxRetries: v4_1.z.number().min(0).max(10),
26765
+ // Optional fallback profile ID from fallbackProfiles namespace
26766
+ fallbackProfileId: v4_1.z.string().optional(),
26737
26767
  // OpenRouter-specific provider routing (ignored for other providers)
26738
26768
  providerAllowlist: v4_1.z.array(v4_1.z.string()).optional(),
26739
26769
  providerBlocklist: v4_1.z.array(v4_1.z.string()).optional()
26740
26770
  });
26741
26771
  exports2.LlmConfigSchema = v4_1.z.object({
26742
26772
  defaultProfile: v4_1.z.string(),
26773
+ defaultFallbackProfileId: v4_1.z.string().optional(),
26743
26774
  profiles: v4_1.z.record(v4_1.z.string(), LlmProfileSchema),
26744
- fallbacks: v4_1.z.record(v4_1.z.string(), LlmProfileSchema).optional(),
26775
+ fallbackProfiles: v4_1.z.record(v4_1.z.string(), LlmProfileSchema).optional(),
26745
26776
  global: v4_1.z.object({
26746
26777
  debugDumpEnabled: v4_1.z.boolean(),
26747
26778
  emulatedProvider: EmulatedProviderSchema.optional()
@@ -26755,10 +26786,29 @@ var require_config2 = __commonJS({
26755
26786
  input: data.defaultProfile
26756
26787
  });
26757
26788
  }
26789
+ if (data.defaultFallbackProfileId && !data.fallbackProfiles?.[data.defaultFallbackProfileId]) {
26790
+ ctx.addIssue({
26791
+ code: "custom",
26792
+ message: `defaultFallbackProfileId "${data.defaultFallbackProfileId}" not found in fallbackProfiles`,
26793
+ path: ["defaultFallbackProfileId"],
26794
+ input: data.defaultFallbackProfileId
26795
+ });
26796
+ }
26797
+ for (const [profileName, profile] of Object.entries(data.profiles)) {
26798
+ if (profile.fallbackProfileId && !data.fallbackProfiles?.[profile.fallbackProfileId]) {
26799
+ ctx.addIssue({
26800
+ code: "custom",
26801
+ message: `Profile "${profileName}" fallbackProfileId "${profile.fallbackProfileId}" not found in fallbackProfiles`,
26802
+ path: ["profiles", profileName, "fallbackProfileId"],
26803
+ input: profile.fallbackProfileId
26804
+ });
26805
+ }
26806
+ }
26758
26807
  }).transform((val) => ({
26759
26808
  defaultProfile: val.defaultProfile,
26809
+ defaultFallbackProfileId: val.defaultFallbackProfileId,
26760
26810
  profiles: val.profiles,
26761
- fallbacks: val.fallbacks ?? {},
26811
+ fallbackProfiles: val.fallbackProfiles ?? {},
26762
26812
  global: val.global ?? { debugDumpEnabled: false, emulatedProvider: void 0 }
26763
26813
  }));
26764
26814
  exports2.TranscriptConfigSchema = v4_1.z.object({
@@ -26793,43 +26843,6 @@ var require_config2 = __commonJS({
26793
26843
  }
26794
26844
  return result;
26795
26845
  }
26796
- function parseUnifiedConfig(content, sourcePath) {
26797
- const result = {};
26798
- const overrides = [];
26799
- const warnings = [];
26800
- const sourceLabel = sourcePath ?? "sidekick.config";
26801
- const lines = content.split("\n");
26802
- for (let lineNum = 0; lineNum < lines.length; lineNum++) {
26803
- const line = lines[lineNum];
26804
- const trimmed = line.trim();
26805
- if (!trimmed || trimmed.startsWith("#")) {
26806
- continue;
26807
- }
26808
- const eqIndex = trimmed.indexOf("=");
26809
- const colonIndex = trimmed.indexOf(":");
26810
- if (eqIndex === -1 && colonIndex === -1) {
26811
- warnings.push(`${sourceLabel}:${lineNum + 1}: malformed line (missing '=' or ':'): ${trimmed}`);
26812
- continue;
26813
- }
26814
- const delimIndex = eqIndex === -1 ? colonIndex : colonIndex === -1 ? eqIndex : Math.min(eqIndex, colonIndex);
26815
- const key = trimmed.substring(0, delimIndex).trim();
26816
- const rawValue = trimmed.substring(delimIndex + 1).trim();
26817
- const parts = key.split(".");
26818
- if (parts.length < 2) {
26819
- warnings.push(`${sourceLabel}:${lineNum + 1}: invalid key format (need domain.key): ${key}`);
26820
- continue;
26821
- }
26822
- const domain = parts[0];
26823
- const path = parts.slice(1);
26824
- const value = coerceValue(rawValue);
26825
- if (!result[domain]) {
26826
- result[domain] = {};
26827
- }
26828
- setNestedValue(result[domain], path, value);
26829
- overrides.push({ key, value });
26830
- }
26831
- return { config: result, overrides, warnings };
26832
- }
26833
26846
  function coerceValue(raw) {
26834
26847
  if (raw === "true")
26835
26848
  return true;
@@ -26873,13 +26886,6 @@ var require_config2 = __commonJS({
26873
26886
  throw new Error(`Failed to parse YAML at ${filePath}: ${message}`, { cause: err });
26874
26887
  }
26875
26888
  }
26876
- function tryReadUnifiedConfig(filePath) {
26877
- if (!(0, node_fs_1.existsSync)(filePath)) {
26878
- return null;
26879
- }
26880
- const content = (0, node_fs_1.readFileSync)(filePath, "utf8");
26881
- return parseUnifiedConfig(content, filePath);
26882
- }
26883
26889
  function loadEnvFiles(homeDir, projectRoot) {
26884
26890
  const envPaths = [];
26885
26891
  const userEnv = (0, node_path_1.join)(homeDir, ".sidekick", ".env");
@@ -26927,7 +26933,7 @@ var require_config2 = __commonJS({
26927
26933
  }
26928
26934
  return result;
26929
26935
  }
26930
- var EXTERNAL_DEFAULTS_FILES = {
26936
+ exports2.EXTERNAL_DEFAULTS_FILES = {
26931
26937
  core: "defaults/core.defaults.yaml",
26932
26938
  llm: "defaults/llm.defaults.yaml",
26933
26939
  transcript: "defaults/transcript.defaults.yaml",
@@ -26937,16 +26943,16 @@ var require_config2 = __commonJS({
26937
26943
  if (!assets) {
26938
26944
  return null;
26939
26945
  }
26940
- const filePath = EXTERNAL_DEFAULTS_FILES[domain];
26946
+ const filePath = exports2.EXTERNAL_DEFAULTS_FILES[domain];
26941
26947
  return assets.resolveYaml(filePath) ?? null;
26942
26948
  }
26943
- function loadDomainConfig(domain, envConfig, userUnified, userDomainPath, projectUnified, projectDomainPath, projectLocalPath, assets) {
26949
+ function loadDomainConfig(domain, envConfig, userDomainPath, projectDomainPath, projectLocalPath, assets) {
26944
26950
  const sources = [];
26945
26951
  let merged = {};
26946
26952
  const externalDefaults = loadExternalDefaults(domain, assets);
26947
26953
  if (externalDefaults) {
26948
26954
  merged = deepMerge(merged, externalDefaults);
26949
- sources.push({ source: `assets:${EXTERNAL_DEFAULTS_FILES[domain]}`, domain });
26955
+ sources.push({ source: `assets:${exports2.EXTERNAL_DEFAULTS_FILES[domain]}`, domain });
26950
26956
  }
26951
26957
  if (envConfig[domain]) {
26952
26958
  merged = deepMerge(merged, envConfig[domain]);
@@ -26957,10 +26963,6 @@ var require_config2 = __commonJS({
26957
26963
  merged = deepMerge(merged, userDomain);
26958
26964
  sources.push({ source: userDomainPath, domain });
26959
26965
  }
26960
- if (userUnified?.[domain]) {
26961
- merged = deepMerge(merged, userUnified[domain]);
26962
- sources.push({ source: "user:sidekick.config", domain });
26963
- }
26964
26966
  if (projectDomainPath) {
26965
26967
  const projectDomain = tryReadYaml(projectDomainPath);
26966
26968
  if (projectDomain) {
@@ -26968,10 +26970,6 @@ var require_config2 = __commonJS({
26968
26970
  sources.push({ source: projectDomainPath, domain });
26969
26971
  }
26970
26972
  }
26971
- if (projectUnified?.[domain]) {
26972
- merged = deepMerge(merged, projectUnified[domain]);
26973
- sources.push({ source: "project:sidekick.config", domain });
26974
- }
26975
26973
  if (projectLocalPath) {
26976
26974
  const projectLocal = tryReadYaml(projectLocalPath);
26977
26975
  if (projectLocal) {
@@ -26983,7 +26981,7 @@ var require_config2 = __commonJS({
26983
26981
  }
26984
26982
  function validateProfileReferences(config) {
26985
26983
  const validProfiles = new Set(Object.keys(config.llm.profiles));
26986
- const validFallbacks = new Set(Object.keys(config.llm.fallbacks));
26984
+ const validFallbacks = new Set(Object.keys(config.llm.fallbackProfiles));
26987
26985
  const errors = [];
26988
26986
  for (const [featureName, featureConfig] of Object.entries(config.features)) {
26989
26987
  const llmConfig = featureConfig.settings?.llm;
@@ -27016,24 +27014,33 @@ ${errors.join("\n")}`);
27016
27014
  const projectRoot = options.projectRoot;
27017
27015
  loadEnvFiles(homeDir, projectRoot);
27018
27016
  const envConfig = envToConfig(process.env);
27019
- const userUnifiedPath = (0, node_path_1.join)(homeDir, ".sidekick", "sidekick.config");
27020
- const userUnifiedParsed = tryReadUnifiedConfig(userUnifiedPath);
27021
- const projectUnifiedPath = projectRoot ? (0, node_path_1.join)(projectRoot, ".sidekick", "sidekick.config") : null;
27022
- const projectUnifiedParsed = projectUnifiedPath ? tryReadUnifiedConfig(projectUnifiedPath) : null;
27023
- const userUnified = userUnifiedParsed?.config ?? null;
27024
- const projectUnified = projectUnifiedParsed?.config ?? null;
27025
27017
  const userSidekick = (0, node_path_1.join)(homeDir, ".sidekick");
27026
27018
  const projectSidekick = projectRoot ? (0, node_path_1.join)(projectRoot, ".sidekick") : null;
27027
27019
  const domains = ["core", "llm", "transcript", "features"];
27028
27020
  const domainConfigs = {};
27029
27021
  for (const domain of domains) {
27030
- const filename = DOMAIN_FILES[domain];
27022
+ const filename = exports2.DOMAIN_FILES[domain];
27031
27023
  const userDomainPath = (0, node_path_1.join)(userSidekick, filename);
27032
27024
  const projectDomainPath = projectSidekick ? (0, node_path_1.join)(projectSidekick, filename) : null;
27033
- const projectLocalPath = projectSidekick ? (0, node_path_1.join)(projectSidekick, `${filename}.local`) : null;
27034
- const { config } = loadDomainConfig(domain, envConfig, userUnified, userDomainPath, projectUnified, projectDomainPath, projectLocalPath, options.assets);
27025
+ const projectLocalPath = projectSidekick ? (0, node_path_1.join)(projectSidekick, `${filename.replace(".yaml", ".local.yaml")}`) : null;
27026
+ const { config } = loadDomainConfig(domain, envConfig, userDomainPath, projectDomainPath, projectLocalPath, options.assets);
27035
27027
  domainConfigs[domain] = config;
27036
27028
  }
27029
+ const legacyDirs = [userSidekick, projectSidekick].filter(Boolean);
27030
+ for (const dir of legacyDirs) {
27031
+ const legacyPath = (0, node_path_1.join)(dir, "sidekick.config");
27032
+ if ((0, node_fs_1.existsSync)(legacyPath)) {
27033
+ options.logger?.warn(`Legacy sidekick.config found at "${legacyPath}" \u2014 this file is no longer read. Migrate settings to .sidekick/{domain}.yaml files (core.yaml, llm.yaml, transcript.yaml, features.yaml).`);
27034
+ }
27035
+ const oldConfigPath = (0, node_path_1.join)(dir, "config.yaml");
27036
+ if ((0, node_fs_1.existsSync)(oldConfigPath)) {
27037
+ options.logger?.warn(`Renamed config file found at "${oldConfigPath}" \u2014 "config.yaml" has been renamed to "core.yaml". Please rename your file.`);
27038
+ }
27039
+ const oldConfigLocalPath = (0, node_path_1.join)(dir, "config.local.yaml");
27040
+ if ((0, node_fs_1.existsSync)(oldConfigLocalPath)) {
27041
+ options.logger?.warn(`Renamed config file found at "${oldConfigLocalPath}" \u2014 "config.local.yaml" has been renamed to "core.local.yaml". Please rename your file.`);
27042
+ }
27043
+ }
27037
27044
  const result = exports2.SidekickConfigSchema.safeParse(domainConfigs);
27038
27045
  if (!result.success) {
27039
27046
  const issues = result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ");
@@ -27086,38 +27093,10 @@ ${errors.join("\n")}`);
27086
27093
  if (Object.keys(envConfig).length > 0) {
27087
27094
  sources.push("environment");
27088
27095
  }
27089
- const userUnifiedPath = (0, node_path_1.join)(homeDir, ".sidekick", "sidekick.config");
27090
- const userUnifiedParsed = tryReadUnifiedConfig(userUnifiedPath);
27091
- if (userUnifiedParsed) {
27092
- sources.push(userUnifiedPath);
27093
- for (const warning of userUnifiedParsed.warnings) {
27094
- logger?.warn("Config parse warning", { warning });
27095
- }
27096
- if (userUnifiedParsed.overrides.length > 0 && logger) {
27097
- logger.info("User config overrides loaded", {
27098
- source: userUnifiedPath,
27099
- overrides: userUnifiedParsed.overrides
27100
- });
27101
- }
27102
- }
27103
- const projectUnifiedPath = projectRoot ? (0, node_path_1.join)(projectRoot, ".sidekick", "sidekick.config") : null;
27104
- const projectUnifiedParsed = projectUnifiedPath ? tryReadUnifiedConfig(projectUnifiedPath) : null;
27105
- if (projectUnifiedParsed) {
27106
- sources.push(projectUnifiedPath);
27107
- for (const warning of projectUnifiedParsed.warnings) {
27108
- logger?.warn("Config parse warning", { warning });
27109
- }
27110
- if (projectUnifiedParsed.overrides.length > 0 && logger) {
27111
- logger.info("Project config overrides loaded", {
27112
- source: projectUnifiedPath,
27113
- overrides: projectUnifiedParsed.overrides
27114
- });
27115
- }
27116
- }
27117
27096
  const userSidekick = (0, node_path_1.join)(homeDir, ".sidekick");
27118
27097
  const projectSidekick = projectRoot ? (0, node_path_1.join)(projectRoot, ".sidekick") : null;
27119
- for (const domain of Object.keys(DOMAIN_FILES)) {
27120
- const filename = DOMAIN_FILES[domain];
27098
+ for (const domain of Object.keys(exports2.DOMAIN_FILES)) {
27099
+ const filename = exports2.DOMAIN_FILES[domain];
27121
27100
  const userDomainPath = (0, node_path_1.join)(userSidekick, filename);
27122
27101
  if ((0, node_fs_1.existsSync)(userDomainPath)) {
27123
27102
  sources.push(userDomainPath);
@@ -27127,7 +27106,7 @@ ${errors.join("\n")}`);
27127
27106
  if ((0, node_fs_1.existsSync)(projectDomainPath)) {
27128
27107
  sources.push(projectDomainPath);
27129
27108
  }
27130
- const projectLocalPath = (0, node_path_1.join)(projectSidekick, `${filename}.local`);
27109
+ const projectLocalPath = (0, node_path_1.join)(projectSidekick, `${filename.replace(".yaml", ".local.yaml")}`);
27131
27110
  if ((0, node_fs_1.existsSync)(projectLocalPath)) {
27132
27111
  sources.push(projectLocalPath);
27133
27112
  }
@@ -27192,6 +27171,231 @@ ${errors.join("\n")}`);
27192
27171
  }
27193
27172
  });
27194
27173
 
27174
+ // ../sidekick-core/dist/config-writer.js
27175
+ var require_config_writer = __commonJS({
27176
+ "../sidekick-core/dist/config-writer.js"(exports2) {
27177
+ "use strict";
27178
+ var __importDefault = exports2 && exports2.__importDefault || function(mod) {
27179
+ return mod && mod.__esModule ? mod : { "default": mod };
27180
+ };
27181
+ Object.defineProperty(exports2, "__esModule", { value: true });
27182
+ exports2.parseDotPath = parseDotPath;
27183
+ exports2.getNestedValue = getNestedValue;
27184
+ exports2.getScopeFilePath = getScopeFilePath;
27185
+ exports2.configGet = configGet;
27186
+ exports2.configSet = configSet;
27187
+ exports2.configUnset = configUnset;
27188
+ exports2.configList = configList;
27189
+ var node_fs_1 = require("node:fs");
27190
+ var node_os_1 = require("node:os");
27191
+ var node_path_1 = require("node:path");
27192
+ var yaml_1 = __importDefault(require_dist2());
27193
+ var config_1 = require_config2();
27194
+ var VALID_DOMAINS = /* @__PURE__ */ new Set(["core", "llm", "transcript", "features"]);
27195
+ var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
27196
+ function parseDotPath(dotPath) {
27197
+ if (!dotPath || dotPath.trim() === "") {
27198
+ throw new Error("Config path must not be empty");
27199
+ }
27200
+ const segments = dotPath.split(".");
27201
+ const domainCandidate = segments[0];
27202
+ if (!VALID_DOMAINS.has(domainCandidate)) {
27203
+ throw new Error(`Unknown domain "${domainCandidate}". Valid domains: ${[...VALID_DOMAINS].join(", ")}`);
27204
+ }
27205
+ const keyPath = segments.slice(1);
27206
+ for (const key of keyPath) {
27207
+ if (FORBIDDEN_KEYS.has(key)) {
27208
+ throw new Error(`Invalid key segment "${key}" in config path`);
27209
+ }
27210
+ }
27211
+ return {
27212
+ domain: domainCandidate,
27213
+ keyPath
27214
+ };
27215
+ }
27216
+ function getNestedValue(obj, keyPath) {
27217
+ if (keyPath.length === 0) {
27218
+ return obj;
27219
+ }
27220
+ let current = obj;
27221
+ for (const key of keyPath) {
27222
+ if (current === null || current === void 0 || typeof current !== "object") {
27223
+ return void 0;
27224
+ }
27225
+ current = current[key];
27226
+ }
27227
+ return current;
27228
+ }
27229
+ function getScopeFilePath(domain, scope, projectRoot, homeDir) {
27230
+ const filename = config_1.DOMAIN_FILES[domain];
27231
+ switch (scope) {
27232
+ case "user":
27233
+ return (0, node_path_1.join)(homeDir, ".sidekick", filename);
27234
+ case "project":
27235
+ if (!projectRoot)
27236
+ return null;
27237
+ return (0, node_path_1.join)(projectRoot, ".sidekick", filename);
27238
+ case "local":
27239
+ if (!projectRoot)
27240
+ return null;
27241
+ return (0, node_path_1.join)(projectRoot, ".sidekick", filename.replace(".yaml", ".local.yaml"));
27242
+ }
27243
+ }
27244
+ function configGet(dotPath, options = {}) {
27245
+ const { domain, keyPath } = parseDotPath(dotPath);
27246
+ const home = options.homeDir ?? (0, node_os_1.homedir)();
27247
+ if (options.scope) {
27248
+ const filePath = getScopeFilePath(domain, options.scope, options.projectRoot, home);
27249
+ if (!filePath) {
27250
+ return void 0;
27251
+ }
27252
+ const raw = (0, config_1.tryReadYaml)(filePath);
27253
+ if (!raw || Object.keys(raw).length === 0) {
27254
+ return void 0;
27255
+ }
27256
+ const value2 = getNestedValue(raw, keyPath);
27257
+ if (value2 === void 0) {
27258
+ return void 0;
27259
+ }
27260
+ return { value: value2, domain, path: keyPath };
27261
+ }
27262
+ const config = (0, config_1.loadConfig)({
27263
+ projectRoot: options.projectRoot,
27264
+ homeDir: home,
27265
+ assets: options.assets,
27266
+ logger: options.logger
27267
+ });
27268
+ const domainConfig = config[domain];
27269
+ const value = getNestedValue(domainConfig, keyPath);
27270
+ if (value === void 0) {
27271
+ return void 0;
27272
+ }
27273
+ return { value, domain, path: keyPath };
27274
+ }
27275
+ function configSet(dotPath, rawValue, options = {}) {
27276
+ const { domain, keyPath } = parseDotPath(dotPath);
27277
+ if (keyPath.length === 0) {
27278
+ throw new Error('Cannot set an entire domain. Specify a key path (e.g., "core.logging.level")');
27279
+ }
27280
+ const home = options.homeDir ?? (0, node_os_1.homedir)();
27281
+ const scope = options.scope ?? "project";
27282
+ const coercedValue = (0, config_1.coerceValue)(rawValue);
27283
+ const projectRoot = options.projectRoot ?? (scope !== "user" ? process.cwd() : void 0);
27284
+ const filePath = getScopeFilePath(domain, scope, projectRoot, home);
27285
+ if (!filePath) {
27286
+ throw new Error(`Cannot resolve file path for domain "${domain}" at scope "${scope}". Is projectRoot set?`);
27287
+ }
27288
+ const fileExisted = (0, node_fs_1.existsSync)(filePath);
27289
+ const originalContent = fileExisted ? (0, node_fs_1.readFileSync)(filePath, "utf8") : null;
27290
+ let doc;
27291
+ if (fileExisted) {
27292
+ doc = yaml_1.default.parseDocument(originalContent);
27293
+ throwOnYamlErrors(doc, `Failed to parse YAML at "${filePath}"`);
27294
+ } else {
27295
+ doc = seedDocumentFromDefaults(domain, options.assets) ?? new yaml_1.default.Document({});
27296
+ }
27297
+ doc.setIn(keyPath, coercedValue);
27298
+ const dir = (0, node_path_1.dirname)(filePath);
27299
+ if (!(0, node_fs_1.existsSync)(dir)) {
27300
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
27301
+ }
27302
+ (0, node_fs_1.writeFileSync)(filePath, doc.toString(), "utf8");
27303
+ try {
27304
+ (0, config_1.loadConfig)({
27305
+ projectRoot,
27306
+ homeDir: home,
27307
+ assets: options.assets,
27308
+ logger: options.logger
27309
+ });
27310
+ } catch (err) {
27311
+ if (fileExisted) {
27312
+ (0, node_fs_1.writeFileSync)(filePath, originalContent, "utf8");
27313
+ } else {
27314
+ try {
27315
+ (0, node_fs_1.unlinkSync)(filePath);
27316
+ } catch {
27317
+ }
27318
+ }
27319
+ const message = err instanceof Error ? err.message : String(err);
27320
+ throw new Error(`Configuration validation failed after setting "${dotPath}": ${message}`, { cause: err });
27321
+ }
27322
+ return {
27323
+ domain,
27324
+ path: keyPath,
27325
+ value: coercedValue,
27326
+ filePath
27327
+ };
27328
+ }
27329
+ function configUnset(dotPath, options = {}) {
27330
+ const { domain, keyPath } = parseDotPath(dotPath);
27331
+ if (keyPath.length === 0) {
27332
+ throw new Error('Cannot unset an entire domain. Specify a key path (e.g., "core.logging.level")');
27333
+ }
27334
+ const home = options.homeDir ?? (0, node_os_1.homedir)();
27335
+ const scope = options.scope ?? "project";
27336
+ const filePath = getScopeFilePath(domain, scope, options.projectRoot, home);
27337
+ if (!filePath) {
27338
+ throw new Error(`Cannot resolve file path for domain "${domain}" at scope "${scope}". Is projectRoot set?`);
27339
+ }
27340
+ if (!(0, node_fs_1.existsSync)(filePath)) {
27341
+ return { domain, path: keyPath, filePath, existed: false };
27342
+ }
27343
+ const content = (0, node_fs_1.readFileSync)(filePath, "utf8");
27344
+ const doc = yaml_1.default.parseDocument(content);
27345
+ throwOnYamlErrors(doc, `Failed to parse YAML at "${filePath}"`);
27346
+ const existed = doc.getIn(keyPath) !== void 0;
27347
+ if (existed) {
27348
+ doc.deleteIn(keyPath);
27349
+ (0, node_fs_1.writeFileSync)(filePath, doc.toString(), "utf8");
27350
+ }
27351
+ return { domain, path: keyPath, filePath, existed };
27352
+ }
27353
+ function configList(options = {}) {
27354
+ const home = options.homeDir ?? (0, node_os_1.homedir)();
27355
+ const scope = options.scope ?? "project";
27356
+ const entries = [];
27357
+ for (const domain of VALID_DOMAINS) {
27358
+ const filePath = getScopeFilePath(domain, scope, options.projectRoot, home);
27359
+ if (!filePath)
27360
+ continue;
27361
+ const raw = (0, config_1.tryReadYaml)(filePath);
27362
+ if (!raw || Object.keys(raw).length === 0)
27363
+ continue;
27364
+ flattenObject(raw, domain, entries);
27365
+ }
27366
+ return { scope, entries };
27367
+ }
27368
+ function flattenObject(obj, prefix, entries) {
27369
+ for (const [key, value] of Object.entries(obj)) {
27370
+ const path = `${prefix}.${key}`;
27371
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
27372
+ flattenObject(value, path, entries);
27373
+ } else {
27374
+ entries.push({ path, value });
27375
+ }
27376
+ }
27377
+ }
27378
+ function throwOnYamlErrors(doc, context) {
27379
+ if (doc.errors.length > 0) {
27380
+ const messages = doc.errors.map((e) => e.message).join("; ");
27381
+ throw new Error(`${context}: ${messages}`);
27382
+ }
27383
+ }
27384
+ function seedDocumentFromDefaults(domain, assets) {
27385
+ if (!assets)
27386
+ return null;
27387
+ const defaultsRelPath = config_1.EXTERNAL_DEFAULTS_FILES[domain];
27388
+ const defaultsAbsPath = assets.resolvePath(defaultsRelPath);
27389
+ if (!defaultsAbsPath || !(0, node_fs_1.existsSync)(defaultsAbsPath))
27390
+ return null;
27391
+ const raw = (0, node_fs_1.readFileSync)(defaultsAbsPath, "utf8");
27392
+ const doc = yaml_1.default.parseDocument(raw);
27393
+ throwOnYamlErrors(doc, `Invalid bundled defaults YAML for domain "${domain}"`);
27394
+ return doc;
27395
+ }
27396
+ }
27397
+ });
27398
+
27195
27399
  // ../sidekick-core/dist/feature-registry.js
27196
27400
  var require_feature_registry = __commonJS({
27197
27401
  "../sidekick-core/dist/feature-registry.js"(exports2) {
@@ -27797,7 +28001,7 @@ var require_ipc_service = __commonJS({
27797
28001
  this.client = new client_js_1.IpcClient((0, transport_js_1.getSocketPath)(projectDir2), logger, options);
27798
28002
  }
27799
28003
  /**
27800
- * Create IpcService from CoreConfig, using IPC settings from config.yaml.
28004
+ * Create IpcService from CoreConfig, using IPC settings from core.yaml.
27801
28005
  *
27802
28006
  * @param projectDir - Project directory path
27803
28007
  * @param logger - Logger instance
@@ -55449,7 +55653,13 @@ var require_profile_factory = __commonJS({
55449
55653
  }
55450
55654
  /**
55451
55655
  * Creates a provider for a profile, reading config at call time.
55452
- * Wraps with FallbackProvider if fallbackProfile specified.
55656
+ * Wraps with FallbackProvider if a fallback is resolved.
55657
+ *
55658
+ * Fallback resolution cascade:
55659
+ * 1. Explicit fallbackProfileId parameter (caller override)
55660
+ * 2. Profile-level fallbackProfileId (per-profile config)
55661
+ * 3. Global defaultFallbackProfileId (llm config level)
55662
+ * 4. No fallback
55453
55663
  */
55454
55664
  createForProfile(profileId, fallbackProfileId) {
55455
55665
  const profile = this.configService.llm.profiles[profileId];
@@ -55457,13 +55667,14 @@ var require_profile_factory = __commonJS({
55457
55667
  throw new Error(`Profile "${profileId}" not found`);
55458
55668
  }
55459
55669
  const primary = this.createProvider(profile, profileId);
55460
- if (!fallbackProfileId)
55670
+ const resolvedFallbackId = fallbackProfileId ?? profile.fallbackProfileId ?? this.configService.llm.defaultFallbackProfileId;
55671
+ if (!resolvedFallbackId)
55461
55672
  return primary;
55462
- const fallback = this.configService.llm.fallbacks[fallbackProfileId];
55673
+ const fallback = this.configService.llm.fallbackProfiles[resolvedFallbackId];
55463
55674
  if (!fallback) {
55464
- throw new Error(`Fallback profile "${fallbackProfileId}" not found`);
55675
+ throw new Error(`Fallback profile "${resolvedFallbackId}" not found`);
55465
55676
  }
55466
- return new fallback_1.FallbackProvider(primary, [this.createProvider(fallback, fallbackProfileId)], this.logger);
55677
+ return new fallback_1.FallbackProvider(primary, [this.createProvider(fallback, resolvedFallbackId)], this.logger);
55467
55678
  }
55468
55679
  /**
55469
55680
  * Creates provider for the default profile.
@@ -55666,7 +55877,8 @@ var require_gitignore = __commonJS({
55666
55877
  ".sidekick/.env",
55667
55878
  ".sidekick/.env.local",
55668
55879
  ".sidekick/sidekick*.pid",
55669
- ".sidekick/sidekick*.token"
55880
+ ".sidekick/sidekick*.token",
55881
+ ".sidekick/*.local.yaml"
55670
55882
  ];
55671
55883
  async function installGitignoreSection(projectDir2) {
55672
55884
  const gitignorePath = path.join(projectDir2, ".gitignore");
@@ -62148,6 +62360,46 @@ var require_git_status = __commonJS({
62148
62360
  }
62149
62361
  });
62150
62362
 
62363
+ // ../sidekick-core/dist/user-profile-loader.js
62364
+ var require_user_profile_loader = __commonJS({
62365
+ "../sidekick-core/dist/user-profile-loader.js"(exports2) {
62366
+ "use strict";
62367
+ Object.defineProperty(exports2, "__esModule", { value: true });
62368
+ exports2.loadUserProfile = loadUserProfile;
62369
+ var node_fs_1 = require("node:fs");
62370
+ var node_os_1 = require("node:os");
62371
+ var node_path_1 = require("node:path");
62372
+ var yaml_1 = require_dist2();
62373
+ var types_1 = require_dist();
62374
+ function loadUserProfile(options) {
62375
+ const home = options?.homeDir ?? (0, node_os_1.homedir)();
62376
+ const filePath = (0, node_path_1.join)(home, ".sidekick", "user.yaml");
62377
+ if (!(0, node_fs_1.existsSync)(filePath)) {
62378
+ return null;
62379
+ }
62380
+ try {
62381
+ const content = (0, node_fs_1.readFileSync)(filePath, "utf-8");
62382
+ const parsed = (0, yaml_1.parse)(content);
62383
+ const result = types_1.UserProfileSchema.safeParse(parsed);
62384
+ if (!result.success) {
62385
+ options?.logger?.warn("Invalid user profile, ignoring", {
62386
+ path: filePath,
62387
+ errors: result.error.issues.map((i) => i.message)
62388
+ });
62389
+ return null;
62390
+ }
62391
+ return result.data;
62392
+ } catch (err) {
62393
+ options?.logger?.warn("Failed to read user profile", {
62394
+ path: filePath,
62395
+ error: err instanceof Error ? err.message : String(err)
62396
+ });
62397
+ return null;
62398
+ }
62399
+ }
62400
+ }
62401
+ });
62402
+
62151
62403
  // ../sidekick-core/dist/index.js
62152
62404
  var require_dist4 = __commonJS({
62153
62405
  "../sidekick-core/dist/index.js"(exports2) {
@@ -62170,7 +62422,7 @@ var require_dist4 = __commonJS({
62170
62422
  };
62171
62423
  Object.defineProperty(exports2, "__esModule", { value: true });
62172
62424
  exports2.SIDEKICK_SECTION_START = exports2.detectGitignoreStatus = exports2.removeGitignoreSection = exports2.installGitignoreSection = exports2.validateOpenAIKey = exports2.validateOpenRouterKey = exports2.createSetupStatusService = exports2.SetupStatusService = exports2.DaemonClient = exports2.findZombieDaemons = exports2.killZombieDaemons = exports2.killAllDaemons = exports2.logEvent = exports2.LogEvents = exports2.DEFAULT_MAX_FILES = exports2.DEFAULT_ROTATE_SIZE_BYTES = exports2.getComponentLogLevel = exports2.setupGlobalErrorHandlers = exports2.createLoggerFacade = exports2.createLogManager = exports2.createConsoleLogger = exports2.getUserDaemonsDir = exports2.getUserPidPath = exports2.getTokenPath = exports2.getSocketPath = exports2.getProjectHash = exports2.getPidPath = exports2.getLockPath = exports2.IpcService = exports2.IpcServer = exports2.loadPersonaFile = exports2.getDefaultPersonasDir = exports2.discoverPersonas = exports2.createPersonaLoader = exports2.reconstructTranscriptPath = exports2.encodeProjectPath = exports2.isPreCompactEvent = exports2.isStopEvent = exports2.isPostToolUseEvent = exports2.isPreToolUseEvent = exports2.isUserPromptSubmitEvent = exports2.isSessionEndEvent = exports2.isSessionStartEvent = exports2.isTranscriptEvent = exports2.isHookEvent = exports2.MetricsPersistPayloadSchema = exports2.CleanupPayloadSchema = exports2.ResumeGenerationPayloadSchema = exports2.SessionSummaryPayloadSchema = exports2.TaskTypes = void 0;
62173
- exports2.parseGitStatusOutput = exports2.getGitFileStatus = exports2.isInSandbox = exports2.updateDaemonHealth = exports2.readDaemonHealth = exports2.DaemonGlobalLogMetricsDescriptor = exports2.CliLogMetricsDescriptor = exports2.DaemonLogMetricsDescriptor = exports2.CompactionHistoryDescriptor = exports2.TranscriptMetricsDescriptor = exports2.GlobalStateAccessor = exports2.SessionStateAccessor = exports2.globalState = exports2.sessionState = exports2.StateCorruptError = exports2.StateNotFoundError = exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = exports2.getHookDir = exports2.getStagingRoot = exports2.SessionScopedStagingService = exports2.StagingServiceCore = exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = void 0;
62425
+ exports2.loadUserProfile = exports2.parseGitStatusOutput = exports2.getGitFileStatus = exports2.isInSandbox = exports2.updateDaemonHealth = exports2.readDaemonHealth = exports2.DaemonGlobalLogMetricsDescriptor = exports2.CliLogMetricsDescriptor = exports2.DaemonLogMetricsDescriptor = exports2.CompactionHistoryDescriptor = exports2.TranscriptMetricsDescriptor = exports2.GlobalStateAccessor = exports2.SessionStateAccessor = exports2.globalState = exports2.sessionState = exports2.StateCorruptError = exports2.StateNotFoundError = exports2.StateService = exports2.createHookableLogger = exports2.InstrumentedProfileProviderFactory = exports2.InstrumentedLLMProvider = exports2.ServiceFactoryImpl = exports2.TranscriptServiceImpl = exports2.createDefaultTokenUsage = exports2.createDefaultMetrics = exports2.copyWithTimestampSync = exports2.renameWithTimestampSync = exports2.renameWithTimestamp = exports2.copyWithTimestamp = exports2.getTimestampedPath = exports2.extractToolResultPreview = exports2.extractToolCallPreview = exports2.extractTextFromContent = exports2.extractContentPreview = exports2.HandlerRegistryImpl = exports2.extractConsumedTimestamp = exports2.createConsumedFilePattern = exports2.CONSUMED_FILE_PATTERN = exports2.filterActiveReminderFiles = exports2.validatePathSegment = exports2.isValidPathSegment = exports2.getReminderPath = exports2.getHookDir = exports2.getStagingRoot = exports2.SessionScopedStagingService = exports2.StagingServiceCore = exports2.GITIGNORE_ENTRIES = exports2.SIDEKICK_SECTION_END = void 0;
62174
62426
  var types_1 = require_dist();
62175
62427
  Object.defineProperty(exports2, "TaskTypes", { enumerable: true, get: function() {
62176
62428
  return types_1.TaskTypes;
@@ -62237,6 +62489,7 @@ var require_dist4 = __commonJS({
62237
62489
  return persona_loader_1.loadPersonaFile;
62238
62490
  } });
62239
62491
  __exportStar(require_config2(), exports2);
62492
+ __exportStar(require_config_writer(), exports2);
62240
62493
  __exportStar(require_feature_registry(), exports2);
62241
62494
  __exportStar(require_feature_types(), exports2);
62242
62495
  __exportStar(require_client(), exports2);
@@ -62497,6 +62750,10 @@ var require_dist4 = __commonJS({
62497
62750
  Object.defineProperty(exports2, "parseGitStatusOutput", { enumerable: true, get: function() {
62498
62751
  return git_status_1.parseGitStatusOutput;
62499
62752
  } });
62753
+ var user_profile_loader_1 = require_user_profile_loader();
62754
+ Object.defineProperty(exports2, "loadUserProfile", { enumerable: true, get: function() {
62755
+ return user_profile_loader_1.loadUserProfile;
62756
+ } });
62500
62757
  }
62501
62758
  });
62502
62759
 
@@ -69726,7 +69983,8 @@ var require_types2 = __commonJS({
69726
69983
  PAUSE_AND_REFLECT: "pause-and-reflect",
69727
69984
  VERIFY_COMPLETION: "verify-completion",
69728
69985
  REMEMBER_YOUR_PERSONA: "remember-your-persona",
69729
- PERSONA_CHANGED: "persona-changed"
69986
+ PERSONA_CHANGED: "persona-changed",
69987
+ USER_PROFILE: "user-profile"
69730
69988
  };
69731
69989
  }
69732
69990
  });
@@ -71812,6 +72070,66 @@ var require_stage_persona_reminders = __commonJS({
71812
72070
  }
71813
72071
  });
71814
72072
 
72073
+ // ../feature-reminders/dist/handlers/staging/stage-user-profile-reminders.js
72074
+ var require_stage_user_profile_reminders = __commonJS({
72075
+ "../feature-reminders/dist/handlers/staging/stage-user-profile-reminders.js"(exports2) {
72076
+ "use strict";
72077
+ Object.defineProperty(exports2, "__esModule", { value: true });
72078
+ exports2.stageUserProfileRemindersForSession = stageUserProfileRemindersForSession;
72079
+ exports2.registerStageUserProfileReminders = registerStageUserProfileReminders;
72080
+ var core_1 = require_dist4();
72081
+ var types_1 = require_dist();
72082
+ var reminder_utils_js_1 = require_reminder_utils();
72083
+ var types_js_1 = require_types2();
72084
+ var USER_PROFILE_REMINDER_HOOKS = ["UserPromptSubmit", "SessionStart"];
72085
+ async function stageUserProfileRemindersForSession(ctx, sessionId) {
72086
+ const profile = (0, core_1.loadUserProfile)({ logger: ctx.logger });
72087
+ if (!profile) {
72088
+ for (const hook of USER_PROFILE_REMINDER_HOOKS) {
72089
+ await ctx.staging.deleteReminder(hook, types_js_1.ReminderIds.USER_PROFILE);
72090
+ }
72091
+ return;
72092
+ }
72093
+ const templateContext = {
72094
+ user_name: profile.name,
72095
+ user_role: profile.role,
72096
+ user_interests: profile.interests.join(", ")
72097
+ };
72098
+ const reminder = (0, reminder_utils_js_1.resolveReminder)(types_js_1.ReminderIds.USER_PROFILE, {
72099
+ context: templateContext,
72100
+ assets: ctx.assets
72101
+ });
72102
+ if (reminder) {
72103
+ for (const targetHook of USER_PROFILE_REMINDER_HOOKS) {
72104
+ await (0, reminder_utils_js_1.stageReminder)(ctx, targetHook, reminder);
72105
+ }
72106
+ ctx.logger.debug("Staged user profile reminders", { sessionId, userName: profile.name });
72107
+ } else {
72108
+ ctx.logger.warn("Failed to resolve user-profile reminder", { sessionId });
72109
+ }
72110
+ }
72111
+ function registerStageUserProfileReminders(context) {
72112
+ if (!(0, types_1.isDaemonContext)(context))
72113
+ return;
72114
+ context.handlers.register({
72115
+ id: "reminders:stage-user-profile-reminders",
72116
+ priority: 39,
72117
+ // Run after persona reminders (priority 40)
72118
+ filter: { kind: "hook", hooks: ["SessionStart"] },
72119
+ handler: async (event, ctx) => {
72120
+ if (!(0, types_1.isDaemonContext)(ctx))
72121
+ return;
72122
+ if (!(0, types_1.isHookEvent)(event) || !(0, types_1.isSessionStartEvent)(event))
72123
+ return;
72124
+ const daemonCtx = ctx;
72125
+ const sessionId = event.context.sessionId;
72126
+ await stageUserProfileRemindersForSession(daemonCtx, sessionId);
72127
+ }
72128
+ });
72129
+ }
72130
+ }
72131
+ });
72132
+
71815
72133
  // ../feature-reminders/dist/handlers/staging/index.js
71816
72134
  var require_staging2 = __commonJS({
71817
72135
  "../feature-reminders/dist/handlers/staging/index.js"(exports2) {
@@ -71824,6 +72142,7 @@ var require_staging2 = __commonJS({
71824
72142
  var stage_stop_bash_changes_1 = require_stage_stop_bash_changes();
71825
72143
  var unstage_verify_completion_1 = require_unstage_verify_completion();
71826
72144
  var stage_persona_reminders_1 = require_stage_persona_reminders();
72145
+ var stage_user_profile_reminders_1 = require_stage_user_profile_reminders();
71827
72146
  function registerStagingHandlers(context) {
71828
72147
  (0, stage_default_user_prompt_1.registerStageDefaultUserPrompt)(context);
71829
72148
  (0, stage_pause_and_reflect_1.registerStagePauseAndReflect)(context);
@@ -71831,6 +72150,7 @@ var require_staging2 = __commonJS({
71831
72150
  (0, stage_stop_bash_changes_1.registerStageBashChanges)(context);
71832
72151
  (0, unstage_verify_completion_1.registerUnstageVerifyCompletion)(context);
71833
72152
  (0, stage_persona_reminders_1.registerStagePersonaReminders)(context);
72153
+ (0, stage_user_profile_reminders_1.registerStageUserProfileReminders)(context);
71834
72154
  }
71835
72155
  }
71836
72156
  });
@@ -72785,10 +73105,14 @@ var require_types3 = __commonJS({
72785
73105
  resetThreshold: 0.7
72786
73106
  },
72787
73107
  personas: {
73108
+ pinnedPersona: "",
72788
73109
  allowList: "",
72789
73110
  blockList: "disabled",
72790
73111
  resumeFreshnessHours: 4,
72791
- injectPersonaIntoClaude: true
73112
+ injectPersonaIntoClaude: true,
73113
+ defaultLlmProfile: "",
73114
+ llmProfiles: {},
73115
+ weights: {}
72792
73116
  }
72793
73117
  };
72794
73118
  exports2.RESUME_MIN_CONFIDENCE = 0.7;
@@ -72840,12 +73164,28 @@ var require_persona_selection = __commonJS({
72840
73164
  }
72841
73165
  return result;
72842
73166
  }
72843
- function selectRandomPersona(personas) {
73167
+ function selectRandomPersona(personas, weights) {
72844
73168
  if (personas.length === 0) {
72845
73169
  return null;
72846
73170
  }
72847
- const index = Math.floor(Math.random() * personas.length);
72848
- return personas[index];
73171
+ const weighted = personas.map((p) => {
73172
+ const raw = weights?.[p.id];
73173
+ const weight = raw === void 0 ? 1 : Number(raw);
73174
+ return { persona: p, weight };
73175
+ }).filter((entry) => Number.isFinite(entry.weight) && entry.weight > 0);
73176
+ if (weighted.length === 0) {
73177
+ return null;
73178
+ }
73179
+ const totalWeight = weighted.reduce((sum, entry) => sum + entry.weight, 0);
73180
+ const threshold = Math.random() * totalWeight;
73181
+ let accumulated = 0;
73182
+ for (const entry of weighted) {
73183
+ accumulated += entry.weight;
73184
+ if (accumulated > threshold) {
73185
+ return entry.persona;
73186
+ }
73187
+ }
73188
+ return weighted[weighted.length - 1].persona;
72849
73189
  }
72850
73190
  async function selectPersonaForSession(sessionId, config, ctx) {
72851
73191
  const personaConfig = {
@@ -72862,6 +73202,30 @@ var require_persona_selection = __commonJS({
72862
73202
  ctx.logger.warn("No personas found, skipping persona selection", { sessionId });
72863
73203
  return null;
72864
73204
  }
73205
+ const pinnedPersona = personaConfig.pinnedPersona?.trim();
73206
+ if (pinnedPersona) {
73207
+ const pinned = allPersonas.get(pinnedPersona);
73208
+ if (pinned) {
73209
+ const personaState2 = {
73210
+ persona_id: pinned.id,
73211
+ selected_from: [pinned.id],
73212
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
73213
+ };
73214
+ const summaryState2 = (0, state_js_1.createSessionSummaryState)(ctx.stateService);
73215
+ await summaryState2.sessionPersona.write(sessionId, personaState2);
73216
+ ctx.logger.info("Using pinned persona for session", {
73217
+ sessionId,
73218
+ personaId: pinned.id,
73219
+ personaName: pinned.display_name
73220
+ });
73221
+ return pinned.id;
73222
+ }
73223
+ ctx.logger.warn("Pinned persona not found, falling back to random selection", {
73224
+ sessionId,
73225
+ pinnedPersona,
73226
+ availablePersonas: Array.from(allPersonas.keys())
73227
+ });
73228
+ }
72865
73229
  const allowList = parsePersonaList(personaConfig.allowList ?? "");
72866
73230
  const blockList = parsePersonaList(personaConfig.blockList ?? "");
72867
73231
  const eligiblePersonas = filterPersonas(allPersonas, allowList, blockList, ctx.logger);
@@ -72874,7 +73238,15 @@ var require_persona_selection = __commonJS({
72874
73238
  });
72875
73239
  return null;
72876
73240
  }
72877
- const selected = selectRandomPersona(eligiblePersonas);
73241
+ const selected = selectRandomPersona(eligiblePersonas, personaConfig.weights);
73242
+ if (!selected) {
73243
+ ctx.logger.warn("No eligible personas after applying weights", {
73244
+ sessionId,
73245
+ weights: personaConfig.weights,
73246
+ eligibleCount: eligiblePersonas.length
73247
+ });
73248
+ return null;
73249
+ }
72878
73250
  const personaState = {
72879
73251
  persona_id: selected.id,
72880
73252
  selected_from: eligiblePersonas.map((p) => p.id),
@@ -73006,12 +73378,37 @@ var require_persona_utils = __commonJS({
73006
73378
  "../feature-session-summary/dist/handlers/persona-utils.js"(exports2) {
73007
73379
  "use strict";
73008
73380
  Object.defineProperty(exports2, "__esModule", { value: true });
73381
+ exports2.buildUserProfileContext = buildUserProfileContext;
73382
+ exports2.loadUserProfileContext = loadUserProfileContext;
73009
73383
  exports2.buildPersonaContext = buildPersonaContext;
73010
73384
  exports2.stripSurroundingQuotes = stripSurroundingQuotes;
73011
73385
  exports2.loadSessionPersona = loadSessionPersona;
73386
+ exports2.resolvePersonaLlmProfile = resolvePersonaLlmProfile;
73387
+ exports2._resetProfileWarningState = _resetProfileWarningState;
73388
+ exports2.validatePersonaLlmProfile = validatePersonaLlmProfile;
73389
+ exports2.mergePersonaConfig = mergePersonaConfig;
73390
+ exports2.getEffectiveProfile = getEffectiveProfile;
73012
73391
  var core_1 = require_dist4();
73013
73392
  var state_js_1 = require_state4();
73393
+ var types_js_1 = require_types3();
73014
73394
  var DEFAULT_PERSONA_SITUATION = "You are watching over the shoulder of a software developer as they work.";
73395
+ function buildUserProfileContext(profile) {
73396
+ if (!profile) {
73397
+ return {
73398
+ user_name: "",
73399
+ user_role: "",
73400
+ user_interests: ""
73401
+ };
73402
+ }
73403
+ return {
73404
+ user_name: profile.name,
73405
+ user_role: profile.role,
73406
+ user_interests: profile.interests.join(", ")
73407
+ };
73408
+ }
73409
+ function loadUserProfileContext(logger) {
73410
+ return buildUserProfileContext((0, core_1.loadUserProfile)({ logger }));
73411
+ }
73015
73412
  function formatExamples(examples) {
73016
73413
  if (!examples || examples.length === 0)
73017
73414
  return "";
@@ -73065,6 +73462,60 @@ var require_persona_utils = __commonJS({
73065
73462
  const personas = loader.discover();
73066
73463
  return personas.get(result.data.persona_id) ?? null;
73067
73464
  }
73465
+ function resolvePersonaLlmProfile(personaId, personaDef, personaConfig) {
73466
+ const perPersona = personaConfig.llmProfiles?.[personaId];
73467
+ if (perPersona)
73468
+ return perPersona;
73469
+ if (personaDef?.llmProfile)
73470
+ return personaDef.llmProfile;
73471
+ if (personaConfig.defaultLlmProfile)
73472
+ return personaConfig.defaultLlmProfile;
73473
+ return void 0;
73474
+ }
73475
+ var _warnedProfiles = /* @__PURE__ */ new Set();
73476
+ var _erroredDefaults = /* @__PURE__ */ new Set();
73477
+ function _resetProfileWarningState() {
73478
+ _warnedProfiles.clear();
73479
+ _erroredDefaults.clear();
73480
+ }
73481
+ function validatePersonaLlmProfile(resolvedProfile, personaId, featureProfile, availableProfiles, isFromDefault, logger) {
73482
+ if (resolvedProfile in availableProfiles) {
73483
+ return { profileId: resolvedProfile };
73484
+ }
73485
+ if (isFromDefault) {
73486
+ if (!_erroredDefaults.has(resolvedProfile)) {
73487
+ _erroredDefaults.add(resolvedProfile);
73488
+ logger.error("Invalid defaultLlmProfile in persona config", {
73489
+ profileId: resolvedProfile,
73490
+ personaId,
73491
+ availableProfiles: Object.keys(availableProfiles)
73492
+ });
73493
+ }
73494
+ return { errorMessage: `Persona ${personaId}'s profile ${resolvedProfile} is not recognized` };
73495
+ }
73496
+ if (!_warnedProfiles.has(resolvedProfile)) {
73497
+ _warnedProfiles.add(resolvedProfile);
73498
+ logger.warn("Persona LLM profile not found, falling back to feature profile", {
73499
+ resolvedProfile,
73500
+ personaId,
73501
+ fallbackProfile: featureProfile,
73502
+ availableProfiles: Object.keys(availableProfiles)
73503
+ });
73504
+ }
73505
+ return { profileId: featureProfile };
73506
+ }
73507
+ function mergePersonaConfig(config) {
73508
+ return { ...types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG.personas, ...config.personas };
73509
+ }
73510
+ function getEffectiveProfile(persona, llmConfig, config, availableProfiles, logger) {
73511
+ const personaId = persona?.id ?? "";
73512
+ const personaConfig = mergePersonaConfig(config);
73513
+ const resolvedProfile = resolvePersonaLlmProfile(personaId, persona, personaConfig);
73514
+ if (!resolvedProfile) {
73515
+ return { profileId: llmConfig.profile };
73516
+ }
73517
+ return validatePersonaLlmProfile(resolvedProfile, personaId, llmConfig.profile, availableProfiles, resolvedProfile === personaConfig.defaultLlmProfile, logger);
73518
+ }
73068
73519
  }
73069
73520
  });
73070
73521
 
@@ -73366,8 +73817,10 @@ var require_update_summary = __commonJS({
73366
73817
  return;
73367
73818
  }
73368
73819
  const personaContext = (0, persona_utils_js_1.buildPersonaContext)(persona);
73820
+ const userProfileContext = (0, persona_utils_js_1.loadUserProfileContext)(ctx.logger);
73369
73821
  const prompt = interpolateTemplate(promptTemplate, {
73370
73822
  ...personaContext,
73823
+ ...userProfileContext,
73371
73824
  session_title: summary.session_title,
73372
73825
  latest_intent: summary.latest_intent,
73373
73826
  turn_count: ctx.transcript.getMetrics().turnCount,
@@ -73376,7 +73829,16 @@ var require_update_summary = __commonJS({
73376
73829
  maxSnarkyWords: config.maxSnarkyWords
73377
73830
  });
73378
73831
  const llmConfig = config.llm?.snarkyComment ?? types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG.llm.snarkyComment;
73379
- const provider = ctx.profileFactory.createForProfile(llmConfig.profile, llmConfig.fallbackProfile);
73832
+ const profileResult = (0, persona_utils_js_1.getEffectiveProfile)(persona, llmConfig, config, ctx.config.llm.profiles, ctx.logger);
73833
+ if ("errorMessage" in profileResult) {
73834
+ const snarkyState = {
73835
+ message: profileResult.errorMessage,
73836
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
73837
+ };
73838
+ await summaryState.snarkyMessage.write(sessionId, snarkyState);
73839
+ return;
73840
+ }
73841
+ const provider = ctx.profileFactory.createForProfile(profileResult.profileId, llmConfig.fallbackProfile);
73380
73842
  try {
73381
73843
  const response = await provider.complete({
73382
73844
  messages: [{ role: "user", content: prompt }]
@@ -73413,7 +73875,9 @@ var require_update_summary = __commonJS({
73413
73875
  last_task_id: null,
73414
73876
  session_title: summary.session_title,
73415
73877
  snarky_comment: summary.latest_intent,
73416
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
73878
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
73879
+ persona_id: null,
73880
+ persona_display_name: null
73417
73881
  };
73418
73882
  await summaryState.resumeMessage.write(sessionId, resumeState);
73419
73883
  (0, core_1.logEvent)(ctx.logger, core_1.LogEvents.resumeUpdated({ sessionId }, {
@@ -73432,9 +73896,11 @@ var require_update_summary = __commonJS({
73432
73896
  intent_confidence: summary.latest_intent_confidence
73433
73897
  }));
73434
73898
  const personaContext = (0, persona_utils_js_1.buildPersonaContext)(persona);
73899
+ const userProfileContext = (0, persona_utils_js_1.loadUserProfileContext)(ctx.logger);
73435
73900
  const keyPhrases = summary.session_title_key_phrases?.join(", ") ?? "";
73436
73901
  const prompt = interpolateTemplate(promptTemplate, {
73437
73902
  ...personaContext,
73903
+ ...userProfileContext,
73438
73904
  sessionTitle: summary.session_title,
73439
73905
  confidence: summary.session_title_confidence,
73440
73906
  latestIntent: summary.latest_intent,
@@ -73443,7 +73909,15 @@ var require_update_summary = __commonJS({
73443
73909
  maxResumeWords: config.maxResumeWords
73444
73910
  });
73445
73911
  const llmConfig = config.llm?.resumeMessage ?? types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG.llm.resumeMessage;
73446
- const provider = ctx.profileFactory.createForProfile(llmConfig.profile, llmConfig.fallbackProfile);
73912
+ const profileResult = (0, persona_utils_js_1.getEffectiveProfile)(persona, llmConfig, config, ctx.config.llm.profiles, ctx.logger);
73913
+ if ("errorMessage" in profileResult) {
73914
+ ctx.logger.error("Skipping resume generation due to invalid persona profile", {
73915
+ sessionId,
73916
+ errorMessage: profileResult.errorMessage
73917
+ });
73918
+ return;
73919
+ }
73920
+ const provider = ctx.profileFactory.createForProfile(profileResult.profileId, llmConfig.fallbackProfile);
73447
73921
  try {
73448
73922
  const response = await provider.complete({
73449
73923
  messages: [{ role: "user", content: prompt }]
@@ -73454,7 +73928,9 @@ var require_update_summary = __commonJS({
73454
73928
  // Not tracked in summary
73455
73929
  session_title: summary.session_title,
73456
73930
  snarky_comment: snarkyWelcome,
73457
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
73931
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
73932
+ persona_id: persona?.id ?? null,
73933
+ persona_display_name: persona?.display_name ?? null
73458
73934
  };
73459
73935
  await summaryState.resumeMessage.write(sessionId, resumeState);
73460
73936
  (0, core_1.logEvent)(ctx.logger, core_1.LogEvents.resumeUpdated({ sessionId }, {
@@ -73540,10 +74016,12 @@ var require_on_demand_generation = __commonJS({
73540
74016
  };
73541
74017
  }
73542
74018
  const personaContext = (0, persona_utils_js_1.buildPersonaContext)(persona);
74019
+ const userProfileContext = (0, persona_utils_js_1.loadUserProfileContext)(ctx.logger);
73543
74020
  const featureConfig = ctx.config.getFeature("session-summary");
73544
74021
  const config = { ...types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG, ...featureConfig.settings };
73545
74022
  const prompt = (0, update_summary_js_1.interpolateTemplate)(promptTemplate, {
73546
74023
  ...personaContext,
74024
+ ...userProfileContext,
73547
74025
  session_title: summary.session_title,
73548
74026
  latest_intent: summary.latest_intent,
73549
74027
  turn_count: ctx.transcript.getMetrics().turnCount,
@@ -73552,7 +74030,11 @@ var require_on_demand_generation = __commonJS({
73552
74030
  maxSnarkyWords: config.maxSnarkyWords
73553
74031
  });
73554
74032
  const llmConfig = config.llm?.snarkyComment ?? types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG.llm.snarkyComment;
73555
- const provider = ctx.profileFactory.createForProfile(llmConfig.profile, llmConfig.fallbackProfile);
74033
+ const profileResult = (0, persona_utils_js_1.getEffectiveProfile)(persona, llmConfig, config, ctx.config.llm.profiles, ctx.logger);
74034
+ if ("errorMessage" in profileResult) {
74035
+ return { success: false, error: profileResult.errorMessage };
74036
+ }
74037
+ const provider = ctx.profileFactory.createForProfile(profileResult.profileId, llmConfig.fallbackProfile);
73556
74038
  try {
73557
74039
  const response = await provider.complete({
73558
74040
  messages: [{ role: "user", content: prompt }]
@@ -73599,7 +74081,9 @@ var require_on_demand_generation = __commonJS({
73599
74081
  last_task_id: null,
73600
74082
  session_title: summary.session_title,
73601
74083
  snarky_comment: summary.latest_intent,
73602
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
74084
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
74085
+ persona_id: null,
74086
+ persona_display_name: null
73603
74087
  };
73604
74088
  await summaryState.resumeMessage.write(sessionId, resumeState);
73605
74089
  ctx.logger.info("Generated deterministic resume message (disabled persona)", { sessionId });
@@ -73613,6 +74097,7 @@ var require_on_demand_generation = __commonJS({
73613
74097
  };
73614
74098
  }
73615
74099
  const personaContext = (0, persona_utils_js_1.buildPersonaContext)(persona);
74100
+ const userProfileContext = (0, persona_utils_js_1.loadUserProfileContext)(ctx.logger);
73616
74101
  const featureConfig = ctx.config.getFeature("session-summary");
73617
74102
  const config = { ...types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG, ...featureConfig.settings };
73618
74103
  const excerpt = ctx.transcript.getExcerpt({
@@ -73624,6 +74109,7 @@ var require_on_demand_generation = __commonJS({
73624
74109
  const keyPhrases = summary.session_title_key_phrases?.join(", ") ?? "";
73625
74110
  const prompt = (0, update_summary_js_1.interpolateTemplate)(promptTemplate, {
73626
74111
  ...personaContext,
74112
+ ...userProfileContext,
73627
74113
  sessionTitle: summary.session_title,
73628
74114
  confidence: summary.session_title_confidence,
73629
74115
  latestIntent: summary.latest_intent,
@@ -73632,7 +74118,11 @@ var require_on_demand_generation = __commonJS({
73632
74118
  maxResumeWords: config.maxResumeWords
73633
74119
  });
73634
74120
  const llmConfig = config.llm?.resumeMessage ?? types_js_1.DEFAULT_SESSION_SUMMARY_CONFIG.llm.resumeMessage;
73635
- const provider = ctx.profileFactory.createForProfile(llmConfig.profile, llmConfig.fallbackProfile);
74121
+ const profileResult = (0, persona_utils_js_1.getEffectiveProfile)(persona, llmConfig, config, ctx.config.llm.profiles, ctx.logger);
74122
+ if ("errorMessage" in profileResult) {
74123
+ return { success: false, error: profileResult.errorMessage };
74124
+ }
74125
+ const provider = ctx.profileFactory.createForProfile(profileResult.profileId, llmConfig.fallbackProfile);
73636
74126
  try {
73637
74127
  const response = await provider.complete({
73638
74128
  messages: [{ role: "user", content: prompt }]
@@ -73642,7 +74132,9 @@ var require_on_demand_generation = __commonJS({
73642
74132
  last_task_id: null,
73643
74133
  session_title: summary.session_title,
73644
74134
  snarky_comment: snarkyWelcome,
73645
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
74135
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
74136
+ persona_id: persona?.id ?? null,
74137
+ persona_display_name: persona?.display_name ?? null
73646
74138
  };
73647
74139
  await summaryState.resumeMessage.write(sessionId, resumeState);
73648
74140
  ctx.logger.info("Generated resume message on-demand", {
@@ -75958,8 +76450,9 @@ var require_daemon = __commonJS({
75958
76450
  },
75959
76451
  llm: {
75960
76452
  defaultProfile: this.configService.llm.defaultProfile,
76453
+ defaultFallbackProfileId: this.configService.llm.defaultFallbackProfileId,
75961
76454
  profiles: this.configService.llm.profiles,
75962
- fallbacks: this.configService.llm.fallbacks
76455
+ fallbackProfiles: this.configService.llm.fallbackProfiles
75963
76456
  },
75964
76457
  getAll: () => this.configService.getAll(),
75965
76458
  getFeature: (name) => this.configService.getFeature(name)
@@ -76151,8 +76644,9 @@ var require_daemon = __commonJS({
76151
76644
  },
76152
76645
  llm: {
76153
76646
  defaultProfile: this.configService.llm.defaultProfile,
76647
+ defaultFallbackProfileId: this.configService.llm.defaultFallbackProfileId,
76154
76648
  profiles: this.configService.llm.profiles,
76155
- fallbacks: this.configService.llm.fallbacks
76649
+ fallbackProfiles: this.configService.llm.fallbackProfiles
76156
76650
  },
76157
76651
  getAll: () => this.configService.getAll(),
76158
76652
  getFeature: (name) => {
@@ -76232,8 +76726,9 @@ var require_daemon = __commonJS({
76232
76726
  },
76233
76727
  llm: {
76234
76728
  defaultProfile: this.configService.llm.defaultProfile,
76729
+ defaultFallbackProfileId: this.configService.llm.defaultFallbackProfileId,
76235
76730
  profiles: this.configService.llm.profiles,
76236
- fallbacks: this.configService.llm.fallbacks
76731
+ fallbackProfiles: this.configService.llm.fallbackProfiles
76237
76732
  },
76238
76733
  getAll: () => this.configService.getAll(),
76239
76734
  getFeature: (name) => this.configService.getFeature(name)
@@ -76519,8 +77014,9 @@ var require_daemon = __commonJS({
76519
77014
  },
76520
77015
  llm: {
76521
77016
  defaultProfile: this.configService.llm.defaultProfile,
77017
+ defaultFallbackProfileId: this.configService.llm.defaultFallbackProfileId,
76522
77018
  profiles: this.configService.llm.profiles,
76523
- fallbacks: this.configService.llm.fallbacks
77019
+ fallbackProfiles: this.configService.llm.fallbackProfiles
76524
77020
  },
76525
77021
  getAll: () => this.configService.getAll(),
76526
77022
  getFeature: (name) => this.configService.getFeature(name)