profile-context.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /** Launcher-owned profile locations and composition inputs. */
  2. import { join } from 'node:path'
  3. import { composeEntries, loadProfileDirectory, PROFILE_PATCH_FILENAME } from './profile.ts'
  4. import { loadOptionalPatches } from './index.ts'
  5. import type { PatchOptions } from '@deepseek-ai/cordis-plugin-include'
  6. /** Current profile facts; scheduling and mutation belong to their callers. */
  7. export interface ProfileContext {
  8. readonly name: string
  9. readonly dir: string
  10. readonly patchPath: string
  11. readonly installAnchor: string
  12. readonly cwd: string
  13. readonly home: string
  14. /** Bundle packages used to start this process, before any persisted edits. */
  15. readonly startedBundles: readonly string[]
  16. readonly patchReload: 'live' | 'startup'
  17. /** Parsed command-line overlays, applied above profile and home patches. */
  18. readonly overlays: readonly PatchOptions[]
  19. /** Launch-time DSH_TELEMETRY_DISABLED value; any non-empty value opts out. */
  20. readonly telemetryDisabledEnv: string | undefined
  21. }
  22. declare module '@deepseek-ai/cordis' {
  23. interface Context {
  24. /** Present only in a profile launched by dsh. */
  25. profileContext: ProfileContext
  26. }
  27. }
  28. const TELEMETRY_ROW_ID = 'session-telemetry-otel'
  29. /**
  30. * Resolve the telemetry opt-out switch into its boot patch. ANY non-empty
  31. * value (including `'0'`/`'false'`) disables: a privacy switch prefers
  32. * off-by-mistake over on-by-mistake. A composition without the telemetry row
  33. * exports nothing, so the switch is then trivially satisfied and no patch is
  34. * generated — custom profiles need not mount telemetry to run with the
  35. * switch set.
  36. * @param disabledEnv - the raw `DSH_TELEMETRY_DISABLED` value (`undefined` when unset).
  37. * @param hasRow - whether the composition carries the telemetry row.
  38. * @returns the disable patch, or `undefined` when no hard-disable patch is required.
  39. */
  40. export function resolveTelemetryPatch(disabledEnv: string | undefined, hasRow: boolean): PatchOptions | undefined {
  41. if ((disabledEnv ?? '') === '' || !hasRow) return undefined
  42. return { id: TELEMETRY_ROW_ID, disabled: true }
  43. }
  44. /** Read current bundle and user layers with the launch-time overlays.
  45. * @param binName Diagnostic prefix for malformed or missing configuration.
  46. * @param context Data supplied by the profile launcher.
  47. * @returns Detached ordered patches; this function does not update the Loader.
  48. */
  49. export function readProfilePatches(binName: string, context: ProfileContext): PatchOptions[] {
  50. const profile = loadProfileDirectory(binName, context.dir, context.installAnchor)
  51. const patches = structuredClone([
  52. ...profile.layers.flatMap(layer => layer.patches),
  53. ...profile.patches,
  54. ...(loadOptionalPatches(binName, join(context.home, PROFILE_PATCH_FILENAME)) ?? []),
  55. ...context.overlays,
  56. ])
  57. const telemetryPatch = resolveTelemetryPatch(context.telemetryDisabledEnv,
  58. composeEntries([patches]).some(row => row.id === TELEMETRY_ROW_ID))
  59. if (telemetryPatch !== undefined) patches.push(telemetryPatch)
  60. return patches
  61. }