scope.spec.ts 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { resolve } from 'node:path'
  2. import { Context } from '@deepseek-ai/cordis'
  3. import SessionStore, { SESSION_FORMAT_VERSION, SessionId, type SessionHeader } from '@deepseek-ai/dsh-session'
  4. import TypertRegistry from '@deepseek-ai/dsh-typert-registry'
  5. import { describe, expect, it, vi } from 'vitest'
  6. import WorkspaceFiles from '../src/index.ts'
  7. const CAPS = {
  8. maxBytes: 1024,
  9. maxFileBytes: 1024,
  10. maxLines: 100,
  11. maxEntries: 100,
  12. }
  13. function header(id: SessionId, cwd?: string): SessionHeader {
  14. return {
  15. version: SESSION_FORMAT_VERSION,
  16. id,
  17. createdAt: 1,
  18. isSeeded: false,
  19. origin: 'subagent',
  20. ...cwd === undefined ? {} : { cwd },
  21. }
  22. }
  23. describe('Workspace Files Session scope lookup', () => {
  24. it('uses live or stored headers without an Agent and leaves with its plugin', async () => {
  25. const liveId = SessionId('live-subagent')
  26. const coldId = SessionId('cold-subagent')
  27. const fallbackId = SessionId('cold-without-cwd')
  28. const missingId = SessionId('missing')
  29. const liveRoot = resolve('live-workspace')
  30. const coldRoot = resolve('cold-workspace')
  31. const fallbackRoot = resolve('fallback-workspace')
  32. const stat = vi.fn(async (id: SessionId) => {
  33. if (id === coldId) return { header: header(coldId, coldRoot) }
  34. if (id === fallbackId) return { header: header(fallbackId) }
  35. return undefined
  36. })
  37. const ctx = new Context()
  38. ctx.provide('fs', {} as never)
  39. ctx.provide('sandboxPolicy', { workspaceRoot: fallbackRoot } as never)
  40. ctx.provide('sessionPersistence', { stat } as never)
  41. const sessions = await ctx.plugin(SessionStore)
  42. const typert = await ctx.plugin(TypertRegistry)
  43. const workspaceFiles = await ctx.plugin(WorkspaceFiles, CAPS)
  44. try {
  45. ctx.sessions.create(liveId, { meta: { cwd: liveRoot, origin: 'subagent' } })
  46. expect(ctx.get('agents')).toBeUndefined()
  47. const lookup = ctx.typert.lookups.get('workspaceFileScope')
  48. expect(lookup).toMatchObject({
  49. parameter: 'workspaceFileScope',
  50. wire: 'workspaceFileScopeId',
  51. hostTypeSymbol: '@deepseek-ai/dsh-api-workspace-files#WorkspaceFileScope',
  52. wireTypeSymbol: '@deepseek-ai/dsh-session/types#SessionId',
  53. })
  54. if (lookup === undefined) throw new Error('workspaceFileScope lookup did not register')
  55. await expect(lookup.resolve(liveId)).resolves.toEqual({ sessionId: liveId, workspaceRoot: liveRoot })
  56. expect(stat).not.toHaveBeenCalled()
  57. await expect(lookup.resolve(coldId)).resolves.toEqual({ sessionId: coldId, workspaceRoot: coldRoot })
  58. await expect(lookup.resolve(fallbackId)).resolves.toEqual({ sessionId: fallbackId, workspaceRoot: fallbackRoot })
  59. await expect(lookup.resolve(missingId)).resolves.toBeUndefined()
  60. expect(stat.mock.calls.map(([id]) => id)).toEqual([coldId, fallbackId, missingId])
  61. await workspaceFiles.dispose()
  62. expect(ctx.typert.lookups.get('workspaceFileScope')).toBeUndefined()
  63. } finally {
  64. await workspaceFiles.dispose()
  65. await sessions.dispose()
  66. await typert.dispose()
  67. }
  68. })
  69. })