snapshot-spill-locators.ts 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. /** Fixture-only logical locators over real local spill files; preview budgets retain recorded path lengths. */
  2. import type { Context } from '@deepseek-ai/cordis'
  3. import { join, relative, resolve, sep } from 'node:path'
  4. import type { SpillLocator } from '@deepseek-ai/dsh-spill'
  5. import type {} from '@deepseek-ai/dsh-fs'
  6. export const name = 'snapshot-spill-locators'
  7. export const inject = ['spillStore', 'fs']
  8. /** Live storage and recorded locator prefixes supplied by the snapshot owner. */
  9. export interface Config {
  10. root: string
  11. locatorRoot: string
  12. }
  13. /**
  14. * Translate only locators returned by this fixture's real spill backend.
  15. * @param ctx - profile context with real spill and filesystem providers.
  16. * @param config - per-run storage and stable logical prefix.
  17. */
  18. export function apply(ctx: Context, config: Config): void {
  19. const root = resolve(config.root)
  20. const locatorRoot = resolve(config.locatorRoot)
  21. const paths = new Map<string, string>()
  22. const store = ctx.spillStore
  23. const fs = ctx.fs
  24. // oxlint-disable-next-line typescript/unbound-method -- preserve method identity for restoration; calls bind the receiver.
  25. const saveText = store.saveText
  26. // oxlint-disable-next-line typescript/unbound-method -- preserve method identity for restoration; calls bind the receiver.
  27. const resolvePath = fs.resolve
  28. ctx.effect(() => {
  29. store.saveText = async (input) => {
  30. const saved = await saveText.call(store, input)
  31. const suffix = relative(root, saved.locator)
  32. if (suffix.startsWith('..') || resolve(root, suffix) !== saved.locator) {
  33. throw new Error('snapshot spill backend returned a locator outside its live root')
  34. }
  35. const locator = join(locatorRoot, suffix) as SpillLocator
  36. paths.set(locator, saved.locator)
  37. return { ...saved, locator }
  38. }
  39. fs.resolve = async (path, opts) => {
  40. const live = paths.get(path)
  41. if (live !== undefined) {
  42. const target = await resolvePath.call(fs, live, opts)
  43. return { ...target, displayPath: path }
  44. }
  45. if (path.startsWith(locatorRoot + sep)) {
  46. throw new Error('snapshot spill locator was not saved by this run')
  47. }
  48. return resolvePath.call(fs, path, opts)
  49. }
  50. return () => {
  51. store.saveText = saveText
  52. fs.resolve = resolvePath
  53. paths.clear()
  54. }
  55. })
  56. }