@brimveyn/aimux 1.21.0 → 1.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/README.md +27 -25
  2. package/package.json +2 -2
  3. package/src/app-runtime/auto-commit-driver.ts +22 -27
  4. package/src/app-runtime/backend-attach-runtime.ts +43 -36
  5. package/src/app-runtime/backend-runtime-events.ts +107 -88
  6. package/src/app-runtime/editor-actions.ts +201 -0
  7. package/src/app-runtime/git-actions.ts +197 -0
  8. package/src/app-runtime/measure-ref.ts +19 -0
  9. package/src/app-runtime/navigation-actions.ts +213 -0
  10. package/src/app-runtime/project-actions.ts +188 -0
  11. package/src/app-runtime/prompt-injection.ts +123 -0
  12. package/src/app-runtime/selection.ts +29 -0
  13. package/src/app-runtime/settings-actions.ts +156 -0
  14. package/src/app-runtime/setup-actions.ts +237 -0
  15. package/src/app-runtime/side-effect-context.ts +33 -0
  16. package/src/app-runtime/side-effects.ts +302 -1541
  17. package/src/app-runtime/snippet-actions.ts +3 -2
  18. package/src/app-runtime/tab-actions.ts +218 -0
  19. package/src/app-runtime/tab-runtime-timeouts.ts +1 -1
  20. package/src/app-runtime/use-auto-commit-driver.ts +14 -13
  21. package/src/app-runtime/use-backend-runtime.ts +12 -11
  22. package/src/app-runtime/use-directory-search.ts +5 -4
  23. package/src/app-runtime/use-mouse-handlers.ts +2 -1
  24. package/src/app-runtime/{use-workspace-autosave.ts → use-project-autosave.ts} +4 -4
  25. package/src/app-runtime/use-renderer-bindings.ts +2 -1
  26. package/src/app-runtime/use-setup-runner.ts +96 -0
  27. package/src/app-runtime/use-terminal-resize.ts +18 -14
  28. package/src/app-runtime/workspace-actions.ts +366 -0
  29. package/src/app-runtime/workspace-activity.ts +138 -0
  30. package/src/app-runtime/workspace-naming.ts +90 -0
  31. package/src/app.tsx +93 -48
  32. package/src/assets/sounds/bell.wav +0 -0
  33. package/src/assets/sounds/ding.wav +0 -0
  34. package/src/assets/sounds/plane.wav +0 -0
  35. package/src/cli/client/daemon-client.ts +2 -2
  36. package/src/cli/client/project-resolver.ts +112 -0
  37. package/src/cli/commands/project/close.ts +32 -0
  38. package/src/cli/commands/project/create.ts +93 -0
  39. package/src/cli/commands/project/list.ts +25 -0
  40. package/src/cli/commands/project/show.ts +32 -0
  41. package/src/cli/commands/{workspace → project}/switch.ts +19 -19
  42. package/src/cli/commands/tab/await.ts +2 -2
  43. package/src/cli/commands/tab/close.ts +3 -3
  44. package/src/cli/commands/tab/create.ts +74 -73
  45. package/src/cli/commands/tab/focus.ts +3 -3
  46. package/src/cli/commands/tab/list.ts +6 -6
  47. package/src/cli/commands/tab/run.ts +2 -2
  48. package/src/cli/commands/tab/send.ts +2 -2
  49. package/src/cli/commands/tab/snapshot.ts +2 -2
  50. package/src/cli/commands/tab/tail.ts +2 -2
  51. package/src/cli/commands/tab/wait.ts +2 -2
  52. package/src/cli/commands/worker/await.ts +3 -3
  53. package/src/cli/commands/worker/doctor.ts +30 -30
  54. package/src/cli/commands/worker/list.ts +15 -15
  55. package/src/cli/commands/worker/prompt.ts +3 -3
  56. package/src/cli/commands/worker/run.ts +23 -23
  57. package/src/cli/commands/worker/shared.ts +53 -59
  58. package/src/cli/commands/worker/stop.ts +29 -29
  59. package/src/cli/commands/worker/submit.ts +3 -3
  60. package/src/cli/commands/{worktree → workspace}/create-core.ts +26 -26
  61. package/src/cli/commands/workspace/create.ts +30 -68
  62. package/src/cli/commands/workspace/list.ts +52 -9
  63. package/src/cli/commands/workspace/remove.ts +81 -0
  64. package/src/cli/completion/plan.ts +2 -2
  65. package/src/cli/completion/sources.ts +18 -18
  66. package/src/cli/context.ts +13 -13
  67. package/src/cli/flags.ts +30 -10
  68. package/src/cli/index.ts +26 -16
  69. package/src/cli/output.ts +1 -1
  70. package/src/cli/registry.ts +12 -12
  71. package/src/config/loader.ts +16 -5
  72. package/src/config.ts +70 -112
  73. package/src/daemon/catalog-writer.ts +67 -67
  74. package/src/daemon/daemon.ts +205 -201
  75. package/src/daemon/session-manager.ts +39 -39
  76. package/src/daemon/session-registry.ts +14 -14
  77. package/src/git/divergence.ts +33 -2
  78. package/src/git/git-poller.ts +1 -1
  79. package/src/git/git-status.ts +2 -2
  80. package/src/git/{move-worktree.ts → move-workspace.ts} +5 -5
  81. package/src/git/pr-status.ts +1 -1
  82. package/src/git/repo-discovery.ts +1 -1
  83. package/src/git/use-repo-discovery.ts +1 -1
  84. package/src/git/workspace-branch-poller.ts +54 -0
  85. package/src/git/workspace-divergence-poller.ts +65 -0
  86. package/src/git/worktree.ts +29 -0
  87. package/src/index.tsx +4 -4
  88. package/src/input/keymap/help-entries.ts +7 -5
  89. package/src/input/modes/bridge.ts +13 -12
  90. package/src/input/modes/handlers/shared.ts +1 -1
  91. package/src/input/modes/transitions.ts +34 -21
  92. package/src/input/modes/types.ts +48 -31
  93. package/src/ipc/manager-protocol.ts +44 -44
  94. package/src/ipc/protocol.ts +192 -166
  95. package/src/platform/play-sound.ts +184 -0
  96. package/src/platform/project-search.ts +8 -8
  97. package/src/platform/worktree-paths.ts +8 -6
  98. package/src/pty/assistant-question-extractor.ts +1 -1
  99. package/src/pty/assistant-status-detection-loop.ts +79 -55
  100. package/src/pty/assistant-status-detector.ts +40 -15
  101. package/src/pty/command-registry.ts +81 -1
  102. package/src/restart-terminal-manager.ts +1 -1
  103. package/src/services/ai-usage/provider.ts +9 -2
  104. package/src/services/ai-usage/spawn.ts +19 -6
  105. package/src/session-backend/bootstrap.ts +4 -4
  106. package/src/session-backend/local-session-backend.ts +78 -75
  107. package/src/session-backend/remote-session-backend.ts +64 -52
  108. package/src/session-backend/types.ts +43 -32
  109. package/src/settings/live.ts +90 -0
  110. package/src/settings/search.ts +43 -0
  111. package/src/settings/sections/about.ts +49 -0
  112. package/src/settings/sections/appearance.ts +54 -0
  113. package/src/settings/sections/automation.ts +105 -0
  114. package/src/settings/sections/commands.ts +72 -0
  115. package/src/settings/sections/editor.ts +56 -0
  116. package/src/settings/sections/experimental.ts +57 -0
  117. package/src/settings/sections/git.ts +112 -0
  118. package/src/settings/sections/index.ts +95 -0
  119. package/src/settings/sections/integrations.ts +23 -0
  120. package/src/settings/sections/layout.ts +72 -0
  121. package/src/settings/sections/notifications.ts +99 -0
  122. package/src/settings/sections/setup.ts +54 -0
  123. package/src/settings/sections/status-bar.ts +63 -0
  124. package/src/settings/settings-store.ts +207 -0
  125. package/src/settings/types.ts +108 -0
  126. package/src/snippets/run-shell-var.ts +48 -22
  127. package/src/state/actions.ts +342 -0
  128. package/src/state/app-store.ts +2 -1
  129. package/src/state/bars.ts +1 -1
  130. package/src/state/dispatch-ref.ts +1 -1
  131. package/src/state/layout-resize.ts +2 -2
  132. package/src/state/project-catalog.ts +275 -0
  133. package/src/state/project-data.ts +143 -0
  134. package/src/state/{session-persistence.ts → project-persistence.ts} +74 -68
  135. package/src/state/project-save.ts +46 -0
  136. package/src/state/project-workspaces.ts +392 -0
  137. package/src/state/reducers/auto-commit-state.ts +11 -10
  138. package/src/state/reducers/git-commit-modal-state.ts +122 -0
  139. package/src/state/reducers/git-mode-state.ts +1 -1
  140. package/src/state/reducers/git-panel-state.ts +10 -6
  141. package/src/state/reducers/modal-state.ts +290 -681
  142. package/src/state/reducers/multi-repo-state.ts +3 -6
  143. package/src/state/reducers/project-state.ts +312 -0
  144. package/src/state/reducers/settings-state.ts +80 -0
  145. package/src/state/reducers/tab-state.ts +107 -60
  146. package/src/state/reducers/ui-state.ts +4 -3
  147. package/src/state/selectors.ts +49 -37
  148. package/src/state/store.ts +57 -24
  149. package/src/state/types.ts +244 -405
  150. package/src/state/validation.ts +14 -12
  151. package/src/terminal-manager/manager-client.ts +32 -32
  152. package/src/terminal-manager/terminal-manager.ts +24 -24
  153. package/src/ui/components/git/git-panel.tsx +2 -2
  154. package/src/ui/components/git/git-view.tsx +12 -12
  155. package/src/ui/components/git/image-diff/image-diff-view.tsx +1 -1
  156. package/src/ui/components/git/pane/git-pane-widget.tsx +7 -7
  157. package/src/ui/components/layout/sidebar/project-list.tsx +444 -0
  158. package/src/ui/components/layout/sidebar/tab-item.tsx +27 -12
  159. package/src/ui/components/layout/sidebar/use-sidebar-auto-scroll.ts +1 -1
  160. package/src/ui/components/layout/sidebar/workspace-row.tsx +253 -0
  161. package/src/ui/components/layout/status-bar.tsx +6 -2
  162. package/src/ui/components/layout/terminal-pane.tsx +34 -29
  163. package/src/ui/components/layout/top-tab-bar.tsx +46 -36
  164. package/src/ui/components/modals/git/git-commit-modal.tsx +8 -8
  165. package/src/ui/components/modals/{sessions/create-session-modal.tsx → projects/create-project-modal.tsx} +12 -12
  166. package/src/ui/components/modals/{sessions/session-name-modal.tsx → projects/project-name-modal.tsx} +2 -2
  167. package/src/ui/components/modals/{sessions/session-picker-modal.tsx → projects/project-picker-modal.tsx} +33 -35
  168. package/src/ui/components/modals/settings/settings-search-modal.tsx +70 -0
  169. package/src/ui/components/modals/shared/form.tsx +34 -22
  170. package/src/ui/components/modals/shared/picker.tsx +10 -10
  171. package/src/ui/components/modals/shared/{worktree-delete-confirm.tsx → workspace-delete-confirm.tsx} +9 -9
  172. package/src/ui/components/modals/tabs/new-tab-modal.tsx +30 -324
  173. package/src/ui/components/modals/workspace/create-workspace-modal.tsx +101 -0
  174. package/src/ui/components/modals/{worktree/worktree-move-confirm-modal.tsx → workspace/workspace-move-confirm-modal.tsx} +5 -5
  175. package/src/ui/components/modals/{worktree/worktree-move-modal.tsx → workspace/workspace-move-modal.tsx} +29 -27
  176. package/src/ui/components/primitives/input-field.tsx +7 -3
  177. package/src/ui/components/primitives/surface.tsx +3 -0
  178. package/src/ui/components/settings/row-value.tsx +74 -0
  179. package/src/ui/components/settings/settings-row.tsx +78 -0
  180. package/src/ui/components/settings/settings-view.tsx +169 -0
  181. package/src/ui/components/setup/setup-widget.tsx +152 -0
  182. package/src/ui/flash/build-labels.ts +27 -27
  183. package/src/ui/hooks/use-activity-sprite.ts +73 -0
  184. package/src/ui/hooks/use-scroll-active-into-view.ts +26 -0
  185. package/src/ui/{session-ordering.ts → project-ordering.ts} +4 -4
  186. package/src/ui/root.tsx +139 -121
  187. package/src/ui/status-bar-model.ts +48 -34
  188. package/src/ui/terminal-graphics/kitty.ts +28 -2
  189. package/src/ui/terminal-graphics/sprites/done@330/0.png +0 -0
  190. package/src/ui/terminal-graphics/sprites/done@330/1.png +0 -0
  191. package/src/ui/terminal-graphics/sprites/idle@1000/0.png +0 -0
  192. package/src/ui/terminal-graphics/sprites/idle@1000/1.png +0 -0
  193. package/src/ui/terminal-graphics/sprites/waiting@170/0.png +0 -0
  194. package/src/ui/terminal-graphics/sprites/waiting@170/1.png +0 -0
  195. package/src/ui/terminal-graphics/sprites/working@150/0.png +0 -0
  196. package/src/ui/terminal-graphics/sprites/working@150/1.png +0 -0
  197. package/src/ui/terminal-graphics/sprites/working@150/2.png +0 -0
  198. package/src/ui/terminal-graphics/sprites/working@150/3.png +0 -0
  199. package/src/ui/terminal-graphics/sprites.ts +246 -0
  200. package/src/ui/truncate.ts +7 -0
  201. package/src/ui/widgets/registry.tsx +6 -3
  202. package/src/ui/widgets/widget-context-menu.ts +26 -10
  203. package/src/update.ts +2 -2
  204. package/src/app-runtime/session-actions.ts +0 -187
  205. package/src/cli/client/workspace-resolver.ts +0 -110
  206. package/src/cli/commands/workspace/close.ts +0 -32
  207. package/src/cli/commands/workspace/show.ts +0 -32
  208. package/src/cli/commands/worktree/create.ts +0 -55
  209. package/src/cli/commands/worktree/list.ts +0 -68
  210. package/src/cli/commands/worktree/remove.ts +0 -81
  211. package/src/git/worktree-branch-poller.ts +0 -54
  212. package/src/git/worktree-divergence-poller.ts +0 -59
  213. package/src/state/reducers/session-state.ts +0 -262
  214. package/src/state/session-catalog.ts +0 -143
  215. package/src/state/session-worktrees.ts +0 -260
  216. package/src/state/workspace-save.ts +0 -43
  217. package/src/ui/components/layout/sidebar/use-top-tab-bar-auto-scroll.ts +0 -30
  218. package/src/ui/components/layout/sidebar/workspace-list.tsx +0 -418
  219. package/src/ui/components/layout/sidebar/worktree-row.tsx +0 -149
  220. /package/src/ui/{components/git/image-diff → terminal-graphics}/dimensions.ts +0 -0
@@ -1,123 +1,123 @@
1
- import type { SessionRecord, WorktreeRecord } from '../state/types'
1
+ import type { ProjectRecord, WorkspaceRecord } from '../state/types'
2
2
 
3
3
  import { logDebug } from '../debug/input-log'
4
4
  import { createPrefixedId } from '../platform/id'
5
- import { loadSessionCatalog, saveSessionCatalog } from '../state/session-catalog'
6
- import { createEmptyWorkspaceSnapshot } from '../state/session-persistence'
7
- import { createPrimaryWorktree, ensureSessionWorktrees } from '../state/session-worktrees'
5
+ import { loadProjectCatalog, saveProjectCatalog } from '../state/project-catalog'
6
+ import { createEmptyProjectSnapshot } from '../state/project-persistence'
7
+ import { createPrimaryWorkspace, ensureProjectWorkspaces } from '../state/project-workspaces'
8
8
 
9
9
  /**
10
10
  * Catalog mutations invoked by the daemon when NO UI is attached. When a UI
11
11
  * is attached the daemon relays the request as an event and the UI's reducer
12
- * owns the write (so the live workspace snapshot is preserved).
12
+ * owns the write (so the live project snapshot is preserved).
13
13
  *
14
14
  * Each helper is a pure read-modify-write against `aimux-sessions.json` —
15
15
  * safe to call from the daemon process, no React / dispatcher involved.
16
16
  */
17
17
 
18
- export function createWorkspaceInCatalog(name: string, projectPath?: string): SessionRecord {
19
- const sessions = loadSessionCatalog()
18
+ export function createProjectInCatalog(name: string, projectPath?: string): ProjectRecord {
19
+ const projects = loadProjectCatalog()
20
20
  const now = new Date().toISOString()
21
- const session: SessionRecord = {
22
- activeWorktreeId: undefined,
21
+ const project: ProjectRecord = {
22
+ activeWorkspaceId: undefined,
23
23
  createdAt: now,
24
- id: createPrefixedId('session'),
24
+ id: createPrefixedId('project'),
25
25
  lastOpenedAt: now,
26
26
  name,
27
27
  projectPath,
28
+ projectSnapshot: createEmptyProjectSnapshot(),
28
29
  updatedAt: now,
29
- workspaceSnapshot: createEmptyWorkspaceSnapshot(),
30
- worktrees: undefined,
30
+ workspaces: undefined,
31
31
  }
32
32
  if (projectPath != null && projectPath !== '') {
33
- const worktree = createPrimaryWorktree(projectPath, now)
34
- session.activeWorktreeId = worktree.id
35
- session.worktrees = [worktree]
33
+ const workspace = createPrimaryWorkspace(projectPath, now)
34
+ project.activeWorkspaceId = workspace.id
35
+ project.workspaces = [workspace]
36
36
  }
37
- saveSessionCatalog([...sessions, ensureSessionWorktrees(session)])
38
- logDebug('daemon.catalog.createWorkspace', { name, projectPath, sessionId: session.id })
39
- return session
37
+ saveProjectCatalog([...projects, ensureProjectWorkspaces(project)])
38
+ logDebug('daemon.catalog.createProject', { name, projectId: project.id, projectPath })
39
+ return project
40
40
  }
41
41
 
42
42
  /**
43
- * Throws when the target session isn't in the catalog. Used by the daemon
44
- * before broadcasting a workspace-lifecycle request so the CLI's `expectOk`
43
+ * Throws when the target project isn't in the catalog. Used by the daemon
44
+ * before broadcasting a project-lifecycle request so the CLI's `expectOk`
45
45
  * fails fast (with a meaningful message) instead of the `--wait` path
46
46
  * hanging out for its timeout while the UI silently ignores an unknown id.
47
47
  */
48
- export function assertSessionInCatalog(sessionId: string): void {
49
- const sessions = loadSessionCatalog()
50
- if (!sessions.some((s) => s.id === sessionId)) {
51
- throw new Error(`workspace not found: ${sessionId}`)
48
+ export function assertProjectInCatalog(projectId: string): void {
49
+ const projects = loadProjectCatalog()
50
+ if (!projects.some((s) => s.id === projectId)) {
51
+ throw new Error(`project not found: ${projectId}`)
52
52
  }
53
53
  }
54
54
 
55
- export function bumpLastOpenedInCatalog(sessionId: string): void {
56
- const sessions = loadSessionCatalog()
55
+ export function bumpLastOpenedInCatalog(projectId: string): void {
56
+ const projects = loadProjectCatalog()
57
57
  const now = new Date().toISOString()
58
- const target = sessions.find((s) => s.id === sessionId)
58
+ const target = projects.find((s) => s.id === projectId)
59
59
  if (!target) {
60
- throw new Error(`workspace not found: ${sessionId}`)
60
+ throw new Error(`project not found: ${projectId}`)
61
61
  }
62
- const updated = sessions.map((s) => (s.id === sessionId ? { ...s, lastOpenedAt: now } : s))
63
- saveSessionCatalog(updated)
64
- logDebug('daemon.catalog.switchWorkspace', { sessionId })
62
+ const updated = projects.map((s) => (s.id === projectId ? { ...s, lastOpenedAt: now } : s))
63
+ saveProjectCatalog(updated)
64
+ logDebug('daemon.catalog.switchProject', { projectId })
65
65
  }
66
66
 
67
- export function deleteFromCatalog(sessionId: string): void {
68
- const sessions = loadSessionCatalog()
69
- const remaining = sessions.filter((s) => s.id !== sessionId)
70
- if (remaining.length === sessions.length) {
71
- throw new Error(`workspace not found: ${sessionId}`)
67
+ export function deleteFromCatalog(projectId: string): void {
68
+ const projects = loadProjectCatalog()
69
+ const remaining = projects.filter((s) => s.id !== projectId)
70
+ if (remaining.length === projects.length) {
71
+ throw new Error(`project not found: ${projectId}`)
72
72
  }
73
- saveSessionCatalog(remaining)
74
- logDebug('daemon.catalog.closeWorkspace', { sessionId })
73
+ saveProjectCatalog(remaining)
74
+ logDebug('daemon.catalog.closeProject', { projectId })
75
75
  }
76
76
 
77
- export function addWorktreeToCatalog(sessionId: string, worktree: WorktreeRecord): void {
78
- const sessions = loadSessionCatalog()
79
- const target = sessions.find((s) => s.id === sessionId)
77
+ export function addWorkspaceToCatalog(projectId: string, workspace: WorkspaceRecord): void {
78
+ const projects = loadProjectCatalog()
79
+ const target = projects.find((s) => s.id === projectId)
80
80
  if (!target) {
81
- throw new Error(`workspace not found: ${sessionId}`)
81
+ throw new Error(`project not found: ${projectId}`)
82
82
  }
83
- const existing = target.worktrees ?? []
84
- if (existing.some((w) => w.id === worktree.id)) {
85
- throw new Error(`worktree already exists: ${worktree.id}`)
83
+ const existing = target.workspaces ?? []
84
+ if (existing.some((w) => w.id === workspace.id)) {
85
+ throw new Error(`workspace already exists: ${workspace.id}`)
86
86
  }
87
- const updated = sessions.map((s) =>
88
- s.id === sessionId
89
- ? { ...s, updatedAt: new Date().toISOString(), worktrees: [...existing, worktree] }
87
+ const updated = projects.map((s) =>
88
+ s.id === projectId
89
+ ? { ...s, updatedAt: new Date().toISOString(), workspaces: [...existing, workspace] }
90
90
  : s
91
91
  )
92
- saveSessionCatalog(updated)
93
- logDebug('daemon.catalog.addWorktree', {
94
- sessionId,
95
- worktreeId: worktree.id,
96
- worktreeName: worktree.name,
92
+ saveProjectCatalog(updated)
93
+ logDebug('daemon.catalog.addWorkspace', {
94
+ projectId,
95
+ workspaceId: workspace.id,
96
+ workspaceName: workspace.name,
97
97
  })
98
98
  }
99
99
 
100
- export function removeWorktreeFromCatalog(sessionId: string, worktreeId: string): void {
101
- const sessions = loadSessionCatalog()
102
- const target = sessions.find((s) => s.id === sessionId)
100
+ export function removeWorkspaceFromCatalog(projectId: string, workspaceId: string): void {
101
+ const projects = loadProjectCatalog()
102
+ const target = projects.find((s) => s.id === projectId)
103
103
  if (!target) {
104
- throw new Error(`workspace not found: ${sessionId}`)
104
+ throw new Error(`project not found: ${projectId}`)
105
105
  }
106
- const existing = target.worktrees ?? []
107
- const nextWorktrees = existing.filter((w) => w.id !== worktreeId)
108
- if (nextWorktrees.length === existing.length) {
109
- throw new Error(`worktree not found: ${worktreeId}`)
106
+ const existing = target.workspaces ?? []
107
+ const nextWorkspaces = existing.filter((w) => w.id !== workspaceId)
108
+ if (nextWorkspaces.length === existing.length) {
109
+ throw new Error(`workspace not found: ${workspaceId}`)
110
110
  }
111
- const updated = sessions.map((s) =>
112
- s.id === sessionId
111
+ const updated = projects.map((s) =>
112
+ s.id === projectId
113
113
  ? {
114
114
  ...s,
115
- activeWorktreeId: s.activeWorktreeId === worktreeId ? undefined : s.activeWorktreeId,
115
+ activeWorkspaceId: s.activeWorkspaceId === workspaceId ? undefined : s.activeWorkspaceId,
116
116
  updatedAt: new Date().toISOString(),
117
- worktrees: nextWorktrees,
117
+ workspaces: nextWorkspaces,
118
118
  }
119
119
  : s
120
120
  )
121
- saveSessionCatalog(updated)
122
- logDebug('daemon.catalog.removeWorktree', { sessionId, worktreeId })
121
+ saveProjectCatalog(updated)
122
+ logDebug('daemon.catalog.removeWorkspace', { projectId, workspaceId })
123
123
  }