profile-context.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. /** Launcher-owned profile locations and composition inputs. */
  2. import { join } from 'node:path'
  3. import { composeEntries, loadProfileDirectory, PROFILE_PATCH_FILENAME, type Profile } 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. /** Parsed command-line overlays, applied above profile and home patches. */
  17. readonly overlays: readonly PatchOptions[]
  18. /** Launch-time DSH_TELEMETRY_DISABLED value; any non-empty value opts out. */
  19. readonly telemetryDisabledEnv: string | undefined
  20. }
  21. declare module '@deepseek-ai/cordis' {
  22. interface Context {
  23. /** Present only in a profile launched by dsh. */
  24. profileContext: ProfileContext
  25. }
  26. }
  27. const TELEMETRY_ROW_ID = 'session-telemetry-otel'
  28. /**
  29. * Resolve the telemetry opt-out switch into its boot patch. ANY non-empty
  30. * value (including `'0'`/`'false'`) disables: a privacy switch prefers
  31. * off-by-mistake over on-by-mistake. A composition without the telemetry row
  32. * exports nothing, so the switch is then trivially satisfied and no patch is
  33. * generated — custom profiles need not mount telemetry to run with the
  34. * switch set.
  35. * @param disabledEnv - the raw `DSH_TELEMETRY_DISABLED` value (`undefined` when unset).
  36. * @param hasRow - whether the composition carries the telemetry row.
  37. * @returns the disable patch, or `undefined` when no hard-disable patch is required.
  38. */
  39. export function resolveTelemetryPatch(disabledEnv: string | undefined, hasRow: boolean): PatchOptions | undefined {
  40. if ((disabledEnv ?? '') === '' || !hasRow) return undefined
  41. return { id: TELEMETRY_ROW_ID, disabled: true }
  42. }
  43. /** Read current bundle and user layers with the launch-time overlays.
  44. * @param binName Diagnostic prefix for malformed or missing configuration.
  45. * @param context Data supplied by the profile launcher.
  46. * @param initialProfile Already loaded startup profile; omitted reads the current files.
  47. * @returns Detached ordered patches; this function does not update the Loader.
  48. */
  49. export function readProfilePatches(binName: string, context: ProfileContext, initialProfile?: Profile): PatchOptions[] {
  50. const profile = initialProfile ?? loadProfileDirectory(binName, context.dir, context.installAnchor, { userLayer: false })
  51. const patches = structuredClone([
  52. ...profile.layers.flatMap(layer => layer.patches),
  53. ...(initialProfile?.patches ?? loadOptionalPatches(binName, context.patchPath) ?? []),
  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. }