@threadbase-sh/streamer 1.52.3 → 1.52.4

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/index.cjs CHANGED
@@ -537,11 +537,12 @@ function validateFeatureFlagValues(raw) {
537
537
  const out = {};
538
538
  const dropped = [];
539
539
  for (const [id, value] of Object.entries(raw)) {
540
- if (!findFeatureFlag(id) || typeof value !== "boolean") {
540
+ const def = findFeatureFlag(id);
541
+ if (!def || typeof value !== "boolean") {
541
542
  dropped.push(id);
542
543
  continue;
543
544
  }
544
- out[id] = value;
545
+ out[def.id] = value;
545
546
  }
546
547
  if (dropped.length > 0) {
547
548
  getLogger("feature-flags").warn(
@@ -556,15 +557,29 @@ function validateFeatureFlagValues(raw) {
556
557
  }
557
558
  function resolveFeatureFlags(opts) {
558
559
  const env = opts?.env ?? process.env;
559
- const out = {};
560
+ const values = {};
561
+ const sources = {};
560
562
  for (const def of FEATURE_FLAGS) {
561
- out[def.id] = parseBooleanEnv(env[def.env]) ?? opts?.cli?.[def.id] ?? opts?.yaml?.[def.id] ?? def.default;
563
+ const rungs = [
564
+ ["override", opts?.override?.[def.id]],
565
+ ["env", parseBooleanEnv(env[def.env])],
566
+ ["cli", opts?.cli?.[def.id]],
567
+ ["yaml", opts?.yaml?.[def.id]]
568
+ ];
569
+ const won = rungs.find(([, v]) => v !== void 0);
570
+ values[def.id] = won ? won[1] : def.default;
571
+ sources[def.id] = won ? won[0] : "default";
562
572
  }
563
- return out;
573
+ return { values, sources };
564
574
  }
565
575
  function nonDefaultFeatureFlags(values) {
566
576
  return FEATURE_FLAGS.filter((f) => values[f.id] !== f.default).map((f) => f.id);
567
577
  }
578
+ function describeFeatureFlags(resolution) {
579
+ return FEATURE_FLAGS.map(
580
+ (f) => `${f.id}=${resolution.values[f.id]}(${resolution.sources[f.id]})`
581
+ ).join(" ");
582
+ }
568
583
 
569
584
  // src/auth.ts
570
585
  function configDir() {
@@ -14496,6 +14511,10 @@ var StreamerServer = class {
14496
14511
  // Resolved once at boot; see src/feature-flags.ts. Total map — every registry
14497
14512
  // id is present, so indexing it never yields undefined.
14498
14513
  featureFlags;
14514
+ // Which rung of the precedence chain decided each flag. Reported at boot and
14515
+ // over GET /api/config/feature-flags — the resolved boolean alone cannot say
14516
+ // whether a value came from the environment, the CLI, server.yaml or nowhere.
14517
+ featureFlagSources;
14499
14518
  // Derived from featureFlags.codexSystemPrompt. Kept as its own field so the
14500
14519
  // read site in startFresh() is unchanged.
14501
14520
  codexSystemPromptEnabled;
@@ -14609,10 +14628,13 @@ var StreamerServer = class {
14609
14628
  this.codexRoots = config.codexRoots ?? [(0, import_path22.join)((0, import_os12.homedir)(), ".codex", "sessions")];
14610
14629
  this.ptyGracePeriodMs = config.ptyGracePeriodMs ?? DEFAULT_PTY_GRACE_PERIOD_MS;
14611
14630
  this.defaultSystemPrompt = config.defaultSystemPrompt ?? DEFAULT_SYSTEM_PROMPT;
14612
- this.featureFlags = resolveFeatureFlags({ cli: config.featureFlags, yaml: loadFeatureFlags() });
14613
- if (config.codexSystemPromptEnabled !== void 0) {
14614
- this.featureFlags.codexSystemPrompt = config.codexSystemPromptEnabled;
14615
- }
14631
+ const flagResolution = resolveFeatureFlags({
14632
+ override: config.codexSystemPromptEnabled === void 0 ? void 0 : { codexSystemPrompt: config.codexSystemPromptEnabled },
14633
+ cli: config.featureFlags,
14634
+ yaml: loadFeatureFlags()
14635
+ });
14636
+ this.featureFlags = flagResolution.values;
14637
+ this.featureFlagSources = flagResolution.sources;
14616
14638
  this.codexSystemPromptEnabled = this.featureFlags.codexSystemPrompt;
14617
14639
  this.defaultPermissionMode = config.defaultPermissionMode ?? loadDefaultPermissionMode() ?? "acceptEdits";
14618
14640
  this.defaultModel = config.defaultModel ?? "sonnet";
@@ -14657,13 +14679,12 @@ var StreamerServer = class {
14657
14679
  });
14658
14680
  this.includeAgents = parseIncludeAgentsEnv(process.env.THREADBASE_INCLUDE_AGENTS);
14659
14681
  this.agentEntrypoints = parseAgentEntrypointsEnv(process.env.THREADBASE_AGENT_ENTRYPOINTS);
14660
- const enabledFlags = nonDefaultFeatureFlags(this.featureFlags);
14661
- if (enabledFlags.length > 0) {
14662
- this.log.info(`Feature flags active: ${enabledFlags.join(", ")}`, {
14663
- event: "config.feature_flags_active",
14664
- flags: enabledFlags
14665
- });
14666
- }
14682
+ this.log.info(`Feature flags: ${describeFeatureFlags(flagResolution)}`, {
14683
+ event: "config.feature_flags",
14684
+ values: this.featureFlags,
14685
+ sources: this.featureFlagSources,
14686
+ nonDefault: nonDefaultFeatureFlags(this.featureFlags)
14687
+ });
14667
14688
  const rawRoot = process.env.THREADBASE_BROWSE_ROOT ?? loadBrowseRoot() ?? config.browseRoot;
14668
14689
  if (rawRoot) {
14669
14690
  (0, import_promises7.realpath)(rawRoot).then((resolved) => {
@@ -15686,7 +15707,11 @@ var StreamerServer = class {
15686
15707
  * the absence of that field is the signal that this endpoint is read-only.
15687
15708
  */
15688
15709
  getFeatureFlagsConfig() {
15689
- return { registry: FEATURE_FLAGS, values: this.featureFlags };
15710
+ return {
15711
+ registry: FEATURE_FLAGS,
15712
+ values: this.featureFlags,
15713
+ sources: this.featureFlagSources
15714
+ };
15690
15715
  }
15691
15716
  getClaudeFlagsConfig() {
15692
15717
  return {