workspace.client.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. /**
  2. * The Remote side of one Workspace registry under test: default answers for
  3. * every `workspace/*` command a `ClientWorkspaceModel` calls, builders for the
  4. * rows and frames of the `workspace/follow` stream, and a script that hands
  5. * each physical generation of that stream to its own script. The stream's
  6. * boot-time opening baseline lives in `remoteDefaultResponses`.
  7. */
  8. import { ok, type RemoteTable, type StreamScript } from '@deepseek-ai/dsh-remote-mock'
  9. import type { RemoteFailure, RemoteResult } from '@deepseek-ai/dsh-typert-protocol'
  10. import type {
  11. WorkspaceArchiveSessionRequest,
  12. WorkspaceArchiveValue,
  13. WorkspaceCreateRequest,
  14. WorkspaceCreateValue,
  15. WorkspaceDeleteRequest,
  16. WorkspaceDeleteValue,
  17. WorkspaceFollowFrame,
  18. WorkspaceId,
  19. WorkspaceInsertBeforeRequest,
  20. WorkspaceInsertSessionBeforeRequest,
  21. WorkspaceOrderValue,
  22. WorkspaceRenameRequest,
  23. WorkspaceUnarchiveSessionRequest,
  24. WorkspaceValue,
  25. WorkspaceView,
  26. } from '../../src/types.ts'
  27. /** The Workspace state stream endpoint. */
  28. export const FOLLOW = 'workspace/follow'
  29. /** The opening frame of one follow generation. */
  30. export type WorkspaceBaselineFrame = Extract<WorkspaceFollowFrame, { type: 'baseline' }>
  31. /**
  32. * The failure branch of a Remote result.
  33. * @param error - the owner-declared failure.
  34. * @returns the result.
  35. */
  36. export function err<T>(error: RemoteFailure): RemoteResult<T> {
  37. return { ok: false, error }
  38. }
  39. /**
  40. * One Workspace row whose id doubles as its title and path segment.
  41. * @param id - Workspace id.
  42. * @param overrides - fields replacing the derived ones.
  43. * @returns the row.
  44. */
  45. export function workspace(id: string, overrides: Partial<WorkspaceView> = {}): WorkspaceView {
  46. return {
  47. workspaceId: id as WorkspaceId,
  48. path: `/work/${id}`,
  49. title: id,
  50. sessionIds: [],
  51. createdAt: '2026-01-01T00:00:00.000Z',
  52. updatedAt: '2026-01-01T00:00:00.000Z',
  53. ...overrides,
  54. }
  55. }
  56. /**
  57. * A baseline frame holding the named Workspaces and no archived Sessions.
  58. * @param ids - Workspace ids in registry order.
  59. * @returns the frame.
  60. */
  61. export function baseline(...ids: readonly string[]): WorkspaceBaselineFrame {
  62. return { type: 'baseline', value: { items: ids.map(id => workspace(id)), archivedSessionIds: [] } }
  63. }
  64. /**
  65. * `workspace/follow` script running the n-th open on the n-th script; an open
  66. * past the last script fails the stream.
  67. * @param generations - one script per physical generation, in open order.
  68. * @returns the script.
  69. */
  70. export function followGenerations(generations: readonly StreamScript[]): StreamScript {
  71. let opened = 0
  72. return (args, stream) => {
  73. const generation = generations[opened++]
  74. if (generation === undefined) throw new Error('no scripted Workspace follow generation')
  75. return generation(args, stream)
  76. }
  77. }
  78. /** Default answers: every command accepted and echoed back as the row or set it names. */
  79. export const workspaceWorld: RemoteTable = {
  80. unary: {
  81. 'workspace/create': (request: WorkspaceCreateRequest): RemoteResult<WorkspaceCreateValue> => ok({
  82. workspace: workspace('created', { path: request.path }), created: true,
  83. }),
  84. 'workspace/rename': (request: WorkspaceRenameRequest): RemoteResult<WorkspaceValue> => ok({
  85. workspace: workspace(String(request.workspaceId), { title: request.title }),
  86. }),
  87. 'workspace/delete': (_request: WorkspaceDeleteRequest): RemoteResult<WorkspaceDeleteValue> => ok({ deleted: true }),
  88. 'workspace/insertBefore': (request: WorkspaceInsertBeforeRequest): RemoteResult<WorkspaceOrderValue> => ok({ workspaceIds: [request.workspaceId] }),
  89. 'workspace/insertSessionBefore': (request: WorkspaceInsertSessionBeforeRequest): RemoteResult<WorkspaceValue> => ok({
  90. workspace: workspace(String(request.workspaceId), { sessionIds: [request.sessionId] }),
  91. }),
  92. 'workspace/archiveSession': (request: WorkspaceArchiveSessionRequest): RemoteResult<WorkspaceArchiveValue> => ok({ archivedSessionIds: [request.sessionId] }),
  93. 'workspace/unarchiveSession': (_request: WorkspaceUnarchiveSessionRequest): RemoteResult<WorkspaceArchiveValue> => ok({ archivedSessionIds: [] }),
  94. },
  95. }