patch.ts 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243
  1. /** Comment-preserving profile plugin enablement edits. */
  2. import { readFile } from 'node:fs/promises'
  3. import { isMap, isSeq, parseDocument } from 'yaml'
  4. import { loadOptionalPatches } from '@deepseek-ai/dsh-app-boot'
  5. import { writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
  6. /** Replace the last matching override or append one after existing insertions.
  7. * @param filename Current profile patch file.
  8. * @param id Unique composition entry id.
  9. * @param name Module name used to match name-qualified overrides.
  10. * @param enabled Desired entry enablement.
  11. * @returns Whether the file changed.
  12. */
  13. export async function writePluginEnabled(filename: string, id: string, name: string, enabled: boolean): Promise<boolean> {
  14. let text: string
  15. try {
  16. text = await readFile(filename, 'utf8')
  17. } catch (error) {
  18. if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error
  19. text = '[]\n'
  20. }
  21. const document = parseDocument(text, {
  22. customTags: [{ tag: 'tag:yaml.org,2002:js', resolve: (value: string) => value }],
  23. })
  24. const error = document.errors[0]
  25. if (error !== undefined) throw error
  26. if (!isSeq(document.contents)) throw new Error('Profile patch must be a YAML sequence')
  27. loadOptionalPatches('dsh', filename)
  28. const items = document.contents.items
  29. const target = items.findLast((item, index) => {
  30. if (!isMap(item) || document.getIn([index, 'id']) !== id || item.has('insert')) return false
  31. const expectedName = document.getIn([index, 'name'])
  32. return !expectedName || expectedName === name
  33. })
  34. if (isMap(target)) {
  35. if (document.getIn([items.indexOf(target), 'disabled']) === !enabled) return false
  36. document.setIn([items.indexOf(target), 'disabled'], !enabled)
  37. } else {
  38. document.add({ id, disabled: !enabled })
  39. }
  40. await writeFileAtomic(filename, String(document), { mode: 0o600 })
  41. return true
  42. }