@promptbook/cli 0.113.0-4 → 0.113.0-8

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 (141) hide show
  1. package/apps/agents-server/src/app/admin/update/AdvancedOriginRepositoryPanel.tsx +76 -0
  2. package/apps/agents-server/src/app/admin/update/CurrentDeploymentCard.tsx +160 -0
  3. package/apps/agents-server/src/app/admin/update/PendingCommitsCard.tsx +86 -0
  4. package/apps/agents-server/src/app/admin/update/TargetEnvironmentCard.tsx +331 -0
  5. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +20 -873
  6. package/apps/agents-server/src/app/admin/update/UpdateJobCard.tsx +329 -0
  7. package/apps/agents-server/src/app/admin/update/UpdateOverview.ts +74 -0
  8. package/apps/agents-server/src/app/admin/update/buildDeploymentTimeBehindLabel.ts +29 -0
  9. package/apps/agents-server/src/app/admin/update/formatHumanReadableTimestamp.ts +18 -0
  10. package/apps/agents-server/src/app/admin/update/getUpdateJobFailureMessage.ts +13 -0
  11. package/apps/agents-server/src/app/admin/update/getUpdateJobSuccessMessage.ts +13 -0
  12. package/apps/agents-server/src/app/admin/update/useUpdateClientState.ts +441 -0
  13. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +13 -1
  14. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageClient.tsx +14 -559
  15. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageHeader.tsx +84 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageSection.tsx +52 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/GeneratedCodePreview.tsx +138 -0
  18. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/GeneratedHarnessSection.tsx +98 -0
  19. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/SourceBookSection.tsx +66 -0
  20. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/TranspiledCodeErrorBanner.tsx +30 -0
  21. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/TranspiledCodeExportWarningBanner.tsx +62 -0
  22. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/Transpiler.ts +9 -0
  23. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/useAgentCodeExportState.ts +478 -0
  24. package/apps/agents-server/src/app/system/utilities/mocked-chats/cloneMockedChatPreset.ts +17 -0
  25. package/apps/agents-server/src/app/system/utilities/mocked-chats/confirmDeleteMockedChat.ts +16 -0
  26. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedMessage.ts +81 -0
  27. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedParticipant.ts +146 -0
  28. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedSettings.ts +19 -0
  29. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDuplicatedDraft.ts +66 -0
  30. package/apps/agents-server/src/app/system/utilities/mocked-chats/findMockedChatById.ts +51 -0
  31. package/apps/agents-server/src/app/system/utilities/mocked-chats/persistMockedChats.ts +51 -0
  32. package/apps/agents-server/src/app/system/utilities/mocked-chats/useMockedChatsEditorState.ts +16 -426
  33. package/apps/agents-server/src/components/Homepage/buildFreeGraphBoxLayout.ts +446 -0
  34. package/apps/agents-server/src/components/Homepage/buildGraphLayoutNodes.ts +415 -157
  35. package/apps/agents-server/src/components/Homepage/useAgentsGraphCanvasState.ts +2 -1
  36. package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +3 -1541
  37. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/LocalSqliteQueryBuilder.ts +623 -0
  38. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/LocalSqliteSupabaseClient.ts +64 -0
  39. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/ensureTable.ts +93 -0
  40. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteFilters.ts +202 -0
  41. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteMutationPayload.ts +131 -0
  42. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteRowOperations.ts +102 -0
  43. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteSql.ts +59 -0
  44. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteTableSchema.ts +329 -0
  45. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteTypes.ts +84 -0
  46. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteValueCodec.ts +63 -0
  47. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/normalizeSqliteError.ts +22 -0
  48. package/apps/agents-server/src/search/createDefaultServerSearchProviders/loadLocalOrganizationSearchDataset.ts +12 -1
  49. package/apps/agents-server/src/tools/send_email.ts +1 -2
  50. package/apps/agents-server/src/utils/agentOrganization/loadAgentOrganizationState.ts +13 -1
  51. package/apps/agents-server/src/utils/backup/createServerBackupZipStream.ts +7 -1382
  52. package/apps/agents-server/src/utils/backup/serverBackup/appendAgentBackupEntriesToZip.ts +27 -0
  53. package/apps/agents-server/src/utils/backup/serverBackup/appendConversationBackupEntriesToZip.ts +140 -0
  54. package/apps/agents-server/src/utils/backup/serverBackup/appendFileBackupEntriesToZip.ts +147 -0
  55. package/apps/agents-server/src/utils/backup/serverBackup/appendMessageBackupEntriesToZip.ts +65 -0
  56. package/apps/agents-server/src/utils/backup/serverBackup/appendMetadataBackupEntriesToZip.ts +39 -0
  57. package/apps/agents-server/src/utils/backup/serverBackup/appendSectionEntriesToZip.ts +92 -0
  58. package/apps/agents-server/src/utils/backup/serverBackup/appendUserBackupEntriesToZip.ts +80 -0
  59. package/apps/agents-server/src/utils/backup/serverBackup/createRedactedWalletBackupRecord.ts +34 -0
  60. package/apps/agents-server/src/utils/backup/serverBackup/createServerBackupManifest.ts +82 -0
  61. package/apps/agents-server/src/utils/backup/serverBackup/downloadBackupBinaryContent.ts +39 -0
  62. package/apps/agents-server/src/utils/backup/serverBackup/resolveFeedbackThreadMessages.ts +53 -0
  63. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupAttachments.ts +151 -0
  64. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupContext.ts +167 -0
  65. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupFilenames.ts +161 -0
  66. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupPreviews.ts +97 -0
  67. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupRowUtilities.ts +158 -0
  68. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupTypes.ts +59 -0
  69. package/apps/agents-server/src/utils/createLocalAgentSourceImporter.ts +159 -0
  70. package/apps/agents-server/src/utils/createMissingImportedAgentFallback.ts +60 -0
  71. package/apps/agents-server/src/utils/customDomainRouting.ts +157 -12
  72. package/apps/agents-server/src/utils/externalChatRunner/processExternalUserChatJob.ts +1 -1
  73. package/apps/agents-server/src/utils/importAgentWithFallback.ts +1 -58
  74. package/apps/agents-server/src/utils/localAgentRouteReferences.ts +167 -0
  75. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +1 -1
  76. package/apps/agents-server/src/utils/managementApi/managementApiAgents.ts +17 -3
  77. package/apps/agents-server/src/utils/messages/sendMessage.ts +5 -3
  78. package/apps/agents-server/src/utils/resolveAgentStateFromSource.ts +7 -1
  79. package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +54 -5
  80. package/apps/agents-server/src/utils/resolveServerAgentContext.ts +12 -1
  81. package/apps/agents-server/src/utils/resolveStoredAgentState.ts +2 -1
  82. package/apps/agents-server/src/utils/speech-to-text/SpeechToTextFailoverRecognition/SpeechToTextFailoverRecognitionProviderRuntime.ts +0 -1
  83. package/apps/agents-server/src/utils/speech-to-text/SpeechToTextFailoverRecognition.ts +34 -2
  84. package/apps/agents-server/src/utils/userChat/userChatMessageLifecycle.ts +39 -9
  85. package/apps/agents-server/tests/e2e/support/ChatHistoryNavigationSupport.ts +5 -0
  86. package/esm/index.es.js +875 -60
  87. package/esm/index.es.js.map +1 -1
  88. package/esm/scripts/find-refactor-candidates/find-refactor-candidates.d.ts +7 -0
  89. package/esm/scripts/find-refactor-candidates/selectMostImportantRefactorCandidates.d.ts +12 -0
  90. package/esm/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +20 -0
  91. package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +5 -0
  92. package/esm/scripts/run-codex-prompts/ui/buildCoderRunAgentVisual.d.ts +29 -0
  93. package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +4 -0
  94. package/esm/src/avatars/renderAvatarVisualAsciiArt.d.ts +75 -0
  95. package/esm/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
  96. package/esm/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
  97. package/esm/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
  98. package/esm/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -0
  99. package/esm/src/cli/cli-commands/common/createPositiveIntegerOptionParser.d.ts +10 -0
  100. package/esm/src/utils/ascii-art/$detectTerminalAnsiColorDepth.d.ts +15 -0
  101. package/esm/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +80 -0
  102. package/esm/src/version.d.ts +1 -1
  103. package/package.json +1 -1
  104. package/src/avatars/avatarAnimationScheduler.ts +2 -1
  105. package/src/avatars/renderAvatarVisualAsciiArt.ts +138 -0
  106. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +6 -2
  107. package/src/avatars/visuals/octopus3d4AvatarVisual.ts +14 -18
  108. package/src/book-components/Chat/Chat/insertDictationChunk.ts +3 -3
  109. package/src/book-components/Chat/Chat/learnDictationDictionary.ts +1 -1
  110. package/src/book-components/Chat/Chat/useChatInputAreaDictation.ts +133 -26
  111. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +3 -1
  112. package/src/cli/cli-commands/coder/boilerplateTemplates.ts +14 -21
  113. package/src/cli/cli-commands/coder/find-refactor-candidates.ts +9 -2
  114. package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +1 -4
  115. package/src/cli/cli-commands/coder/run.ts +3 -27
  116. package/src/cli/cli-commands/common/createPositiveIntegerOptionParser.ts +31 -0
  117. package/src/commitments/TEAM/TEAM.ts +5 -5
  118. package/src/other/templates/getTemplatesPipelineCollection.ts +770 -1169
  119. package/src/utils/ascii-art/$detectTerminalAnsiColorDepth.ts +45 -0
  120. package/src/utils/ascii-art/convertImageDataToAsciiArt.ts +396 -0
  121. package/src/version.ts +2 -2
  122. package/src/versions.txt +2 -0
  123. package/umd/index.umd.js +875 -60
  124. package/umd/index.umd.js.map +1 -1
  125. package/umd/scripts/find-refactor-candidates/find-refactor-candidates.d.ts +7 -0
  126. package/umd/scripts/find-refactor-candidates/selectMostImportantRefactorCandidates.d.ts +12 -0
  127. package/umd/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +20 -0
  128. package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +5 -0
  129. package/umd/scripts/run-codex-prompts/ui/buildCoderRunAgentVisual.d.ts +29 -0
  130. package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +4 -0
  131. package/umd/src/avatars/renderAvatarVisualAsciiArt.d.ts +75 -0
  132. package/umd/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
  133. package/umd/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
  134. package/umd/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
  135. package/umd/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -0
  136. package/umd/src/cli/cli-commands/common/createPositiveIntegerOptionParser.d.ts +10 -0
  137. package/umd/src/utils/ascii-art/$detectTerminalAnsiColorDepth.d.ts +15 -0
  138. package/umd/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +80 -0
  139. package/umd/src/version.d.ts +1 -1
  140. package/esm/scripts/run-codex-prompts/common/resolveAgentSystemMessage.d.ts +0 -6
  141. package/umd/scripts/run-codex-prompts/common/resolveAgentSystemMessage.d.ts +0 -6
@@ -1,27 +1,28 @@
1
1
  import { useMemo, useState } from 'react';
2
- import { showConfirm } from '@/src/components/AsyncDialogs/asyncDialogs';
3
2
  import {
4
3
  createDefaultMockedChatPreset,
5
- createMockedChatId,
6
- createMockedChatMessageId,
7
- createMockedChatParticipantId,
8
4
  type MockedChatParticipant,
9
5
  type MockedChatPreset,
10
6
  type MockedChatScriptedMessage,
11
- type MockedChatSettings,
12
7
  type MockedChatTimingPreset,
13
8
  type MockedChatViewportPreset,
14
9
  } from '@/src/utils/mockedChatsSchema';
15
-
16
- /**
17
- * API endpoint used by the mocked-chat editor.
18
- */
19
- const MOCKED_CHATS_API_ENDPOINT = '/api/system/mocked-chats';
20
-
21
- /**
22
- * Fallback offset distance when adding new scripted messages.
23
- */
24
- const DEFAULT_NEW_MESSAGE_OFFSET_STEP_MS = 1_200;
10
+ import { cloneMockedChatPreset } from './cloneMockedChatPreset';
11
+ import { confirmDeleteMockedChat } from './confirmDeleteMockedChat';
12
+ import { createDraftForSaveAsNew, createDuplicatedDraft, createNormalizedDraftForSave } from './createDuplicatedDraft';
13
+ import {
14
+ createDraftWithAddedMessage,
15
+ createDraftWithRemovedMessage,
16
+ createDraftWithUpdatedMessage,
17
+ } from './createDraftWithUpdatedMessage';
18
+ import {
19
+ createDraftWithAddedParticipant,
20
+ createDraftWithRemovedParticipant,
21
+ createDraftWithUpdatedParticipant,
22
+ } from './createDraftWithUpdatedParticipant';
23
+ import { createDraftWithUpdatedSettings } from './createDraftWithUpdatedSettings';
24
+ import { findMockedChatById, isMockedChatDraftDirty, upsertMockedChatPreset } from './findMockedChatById';
25
+ import { persistMockedChats, resolveMockedChatsActionErrorMessage } from './persistMockedChats';
25
26
 
26
27
  /**
27
28
  * Props for `useMockedChatsEditorState`.
@@ -30,13 +31,6 @@ type UseMockedChatsEditorStateProps = {
30
31
  initialMockedChats: Array<MockedChatPreset>;
31
32
  };
32
33
 
33
- /**
34
- * API payload returned by mocked-chat routes.
35
- */
36
- type MockedChatsApiPayload = {
37
- mockedChats: Array<MockedChatPreset>;
38
- };
39
-
40
34
  /**
41
35
  * Shared state contract used by the private mocked-chat editor modules.
42
36
  *
@@ -92,410 +86,6 @@ type PersistedChatsMutation = {
92
86
  applyPersistedChats: (persistedChats: Array<MockedChatPreset>) => void;
93
87
  };
94
88
 
95
- /**
96
- * Clones one mocked-chat preset so editor state does not mutate saved references.
97
- *
98
- * @private function of <MockedChatsEditorClient/>
99
- */
100
- function cloneMockedChatPreset(preset: MockedChatPreset): MockedChatPreset {
101
- return {
102
- ...preset,
103
- participants: preset.participants.map((participant) => ({ ...participant })),
104
- messages: preset.messages.map((message) => ({ ...message })),
105
- settings: {
106
- ...preset.settings,
107
- },
108
- };
109
- }
110
-
111
- /**
112
- * Finds one mocked chat by id.
113
- *
114
- * @private function of <MockedChatsEditorClient/>
115
- */
116
- function findMockedChatById(
117
- mockedChats: ReadonlyArray<MockedChatPreset>,
118
- mockedChatId: string | null,
119
- ): MockedChatPreset | null {
120
- if (!mockedChatId) {
121
- return null;
122
- }
123
-
124
- return mockedChats.find((mockedChat) => mockedChat.id === mockedChatId) || null;
125
- }
126
-
127
- /**
128
- * Checks whether the draft differs from the selected saved chat.
129
- *
130
- * @private function of <MockedChatsEditorClient/>
131
- */
132
- function isMockedChatDraftDirty(selectedSavedChat: MockedChatPreset | null, draftChat: MockedChatPreset): boolean {
133
- if (!selectedSavedChat) {
134
- return true;
135
- }
136
-
137
- return JSON.stringify(selectedSavedChat) !== JSON.stringify(draftChat);
138
- }
139
-
140
- /**
141
- * Persists one full mocked-chat list and returns server-normalized records.
142
- *
143
- * @private function of <MockedChatsEditorClient/>
144
- */
145
- async function persistMockedChats(nextMockedChats: Array<MockedChatPreset>): Promise<Array<MockedChatPreset>> {
146
- const response = await fetch(MOCKED_CHATS_API_ENDPOINT, {
147
- method: 'PUT',
148
- headers: {
149
- 'Content-Type': 'application/json',
150
- },
151
- body: JSON.stringify({ mockedChats: nextMockedChats }),
152
- });
153
-
154
- const payload = (await response.json().catch(() => ({}))) as Partial<MockedChatsApiPayload> & {
155
- error?: string;
156
- };
157
-
158
- if (!response.ok || !Array.isArray(payload.mockedChats)) {
159
- throw new Error(payload.error || 'Failed to save mocked chats.');
160
- }
161
-
162
- return payload.mockedChats;
163
- }
164
-
165
- /**
166
- * Resolves the user-facing error message for one mocked-chat action.
167
- *
168
- * @private function of <MockedChatsEditorClient/>
169
- */
170
- function resolveMockedChatsActionErrorMessage(error: unknown, fallbackMessage: string): string {
171
- return error instanceof Error ? error.message : fallbackMessage;
172
- }
173
-
174
- /**
175
- * Requests confirmation before deleting one mocked chat.
176
- *
177
- * @private function of <MockedChatsEditorClient/>
178
- */
179
- async function confirmDeleteMockedChat(targetChat: MockedChatPreset): Promise<boolean> {
180
- return showConfirm({
181
- title: 'Delete mocked chat',
182
- message: `Delete "${targetChat.name}"? This cannot be undone.`,
183
- confirmLabel: 'Delete mocked chat',
184
- cancelLabel: 'Cancel',
185
- }).catch(() => false);
186
- }
187
-
188
- /**
189
- * Builds a user-friendly duplicate name.
190
- *
191
- * @private function of <MockedChatsEditorClient/>
192
- */
193
- function buildCopyName(name: string): string {
194
- const trimmedName = name.trim();
195
- if (!trimmedName) {
196
- return 'Untitled mocked chat copy';
197
- }
198
-
199
- return trimmedName.toLowerCase().endsWith('copy') ? trimmedName : `${trimmedName} copy`;
200
- }
201
-
202
- /**
203
- * Creates a local duplicate draft from the current editor content.
204
- *
205
- * @private function of <MockedChatsEditorClient/>
206
- */
207
- function createDuplicatedDraft(draftChat: MockedChatPreset): MockedChatPreset {
208
- const duplicatedDraft = cloneMockedChatPreset(draftChat);
209
- duplicatedDraft.id = createMockedChatId();
210
- duplicatedDraft.name = buildCopyName(draftChat.name);
211
- duplicatedDraft.createdAt = new Date().toISOString();
212
- duplicatedDraft.updatedAt = duplicatedDraft.createdAt;
213
- return duplicatedDraft;
214
- }
215
-
216
- /**
217
- * Normalizes the draft before saving it over its current id.
218
- *
219
- * @private function of <MockedChatsEditorClient/>
220
- */
221
- function createNormalizedDraftForSave(
222
- draftChat: MockedChatPreset,
223
- selectedSavedChat: MockedChatPreset | null,
224
- ): MockedChatPreset {
225
- const nowIso = new Date().toISOString();
226
-
227
- return {
228
- ...cloneMockedChatPreset(draftChat),
229
- name: draftChat.name.trim() || 'Untitled mocked chat',
230
- updatedAt: nowIso,
231
- createdAt: selectedSavedChat?.createdAt || draftChat.createdAt || nowIso,
232
- };
233
- }
234
-
235
- /**
236
- * Creates the saved-copy payload used by "Save as New".
237
- *
238
- * @private function of <MockedChatsEditorClient/>
239
- */
240
- function createDraftForSaveAsNew(draftChat: MockedChatPreset): MockedChatPreset {
241
- const nowIso = new Date().toISOString();
242
-
243
- return {
244
- ...cloneMockedChatPreset(draftChat),
245
- id: createMockedChatId(),
246
- name: buildCopyName(draftChat.name),
247
- createdAt: nowIso,
248
- updatedAt: nowIso,
249
- };
250
- }
251
-
252
- /**
253
- * Upserts one mocked-chat preset by id while preserving list order by updated date.
254
- *
255
- * @private function of <MockedChatsEditorClient/>
256
- */
257
- function upsertMockedChatPreset(
258
- presets: ReadonlyArray<MockedChatPreset>,
259
- incomingPreset: MockedChatPreset,
260
- ): Array<MockedChatPreset> {
261
- const existingIndex = presets.findIndex((preset) => preset.id === incomingPreset.id);
262
- const nextPresets = [...presets];
263
-
264
- if (existingIndex === -1) {
265
- nextPresets.push(incomingPreset);
266
- } else {
267
- nextPresets[existingIndex] = incomingPreset;
268
- }
269
-
270
- return nextPresets.sort((leftPreset, rightPreset) => Date.parse(rightPreset.updatedAt) - Date.parse(leftPreset.updatedAt));
271
- }
272
-
273
- /**
274
- * Creates one participant draft with deterministic defaults.
275
- *
276
- * @private function of <MockedChatsEditorClient/>
277
- */
278
- function createDraftParticipant(participantCount: number): MockedChatParticipant {
279
- return {
280
- id: createMockedChatParticipantId(),
281
- name: `Participant ${participantCount + 1}`,
282
- isMe: participantCount === 0,
283
- bubbleColor: '#2563eb',
284
- avatarUrl: null,
285
- typingAvatarUrl: null,
286
- };
287
- }
288
-
289
- /**
290
- * Ensures at least one participant remains marked as `isMe`.
291
- *
292
- * @private function of <MockedChatsEditorClient/>
293
- */
294
- function ensureParticipantMarkedAsMe(participants: Array<MockedChatParticipant>): Array<MockedChatParticipant> {
295
- if (participants.some((participant) => participant.isMe) || participants.length === 0) {
296
- return participants;
297
- }
298
-
299
- const nextParticipants = [...participants];
300
- nextParticipants[0] = {
301
- ...nextParticipants[0],
302
- isMe: true,
303
- };
304
- return nextParticipants;
305
- }
306
-
307
- /**
308
- * Reconciles message sender ids after participant changes.
309
- *
310
- * @private function of <MockedChatsEditorClient/>
311
- */
312
- function reconcileMessageSenderIds(
313
- messages: ReadonlyArray<MockedChatScriptedMessage>,
314
- participants: ReadonlyArray<MockedChatParticipant>,
315
- fallbackSenderId: string,
316
- ): Array<MockedChatScriptedMessage> {
317
- return messages.map((message) => ({
318
- ...message,
319
- senderId: participants.some((participant) => participant.id === message.senderId)
320
- ? message.senderId
321
- : fallbackSenderId,
322
- }));
323
- }
324
-
325
- /**
326
- * Applies one participant field update and keeps the "me" invariant.
327
- *
328
- * @private function of <MockedChatsEditorClient/>
329
- */
330
- function updateParticipantsAfterFieldChange<TField extends keyof MockedChatParticipant>(
331
- participants: ReadonlyArray<MockedChatParticipant>,
332
- participantId: string,
333
- field: TField,
334
- value: MockedChatParticipant[TField],
335
- ): Array<MockedChatParticipant> {
336
- let nextParticipants = participants.map((participant) => {
337
- if (participant.id !== participantId) {
338
- return participant;
339
- }
340
-
341
- return {
342
- ...participant,
343
- [field]: value,
344
- };
345
- });
346
-
347
- if (field === 'isMe' && value === true) {
348
- nextParticipants = nextParticipants.map((participant) => ({
349
- ...participant,
350
- isMe: participant.id === participantId,
351
- }));
352
- }
353
-
354
- return nextParticipants;
355
- }
356
-
357
- /**
358
- * Resolves the participant used for newly added scripted messages.
359
- *
360
- * @private function of <MockedChatsEditorClient/>
361
- */
362
- function resolveDefaultMessageSenderId(participants: ReadonlyArray<MockedChatParticipant>): string {
363
- return participants.find((participant) => participant.isMe)?.id || participants[0]?.id || 'USER';
364
- }
365
-
366
- /**
367
- * Adds one participant to the current draft.
368
- *
369
- * @private function of <MockedChatsEditorClient/>
370
- */
371
- function createDraftWithAddedParticipant(previousDraft: MockedChatPreset): MockedChatPreset {
372
- const nextParticipants = [...previousDraft.participants, createDraftParticipant(previousDraft.participants.length)];
373
-
374
- return {
375
- ...previousDraft,
376
- participants: nextParticipants,
377
- };
378
- }
379
-
380
- /**
381
- * Updates one participant field in the draft.
382
- *
383
- * @private function of <MockedChatsEditorClient/>
384
- */
385
- function createDraftWithUpdatedParticipant<TField extends keyof MockedChatParticipant>(
386
- previousDraft: MockedChatPreset,
387
- participantId: string,
388
- field: TField,
389
- value: MockedChatParticipant[TField],
390
- ): MockedChatPreset {
391
- const nextParticipants = updateParticipantsAfterFieldChange(previousDraft.participants, participantId, field, value);
392
- const fallbackSenderId = nextParticipants[0]?.id || previousDraft.messages[0]?.senderId || 'USER';
393
-
394
- return {
395
- ...previousDraft,
396
- participants: nextParticipants,
397
- messages: reconcileMessageSenderIds(previousDraft.messages, nextParticipants, fallbackSenderId),
398
- };
399
- }
400
-
401
- /**
402
- * Removes one participant from the draft.
403
- *
404
- * @private function of <MockedChatsEditorClient/>
405
- */
406
- function createDraftWithRemovedParticipant(previousDraft: MockedChatPreset, participantId: string): MockedChatPreset {
407
- const remainingParticipants = previousDraft.participants.filter((participant) => participant.id !== participantId);
408
- if (remainingParticipants.length === 0) {
409
- return previousDraft;
410
- }
411
-
412
- const nextParticipants = ensureParticipantMarkedAsMe(remainingParticipants);
413
- const fallbackSenderId = nextParticipants[0]?.id || 'USER';
414
-
415
- return {
416
- ...previousDraft,
417
- participants: nextParticipants,
418
- messages: reconcileMessageSenderIds(previousDraft.messages, nextParticipants, fallbackSenderId),
419
- };
420
- }
421
-
422
- /**
423
- * Adds one scripted message at the end of the sequence.
424
- *
425
- * @private function of <MockedChatsEditorClient/>
426
- */
427
- function createDraftWithAddedMessage(previousDraft: MockedChatPreset): MockedChatPreset {
428
- const previousOffset = previousDraft.messages[previousDraft.messages.length - 1]?.offsetMs || 0;
429
-
430
- const nextMessage: MockedChatScriptedMessage = {
431
- id: createMockedChatMessageId(),
432
- senderId: resolveDefaultMessageSenderId(previousDraft.participants),
433
- content: 'New scripted message',
434
- offsetMs: previousOffset + DEFAULT_NEW_MESSAGE_OFFSET_STEP_MS,
435
- };
436
-
437
- return {
438
- ...previousDraft,
439
- messages: [...previousDraft.messages, nextMessage],
440
- };
441
- }
442
-
443
- /**
444
- * Updates one scripted message field.
445
- *
446
- * @private function of <MockedChatsEditorClient/>
447
- */
448
- function createDraftWithUpdatedMessage<TField extends keyof MockedChatScriptedMessage>(
449
- previousDraft: MockedChatPreset,
450
- messageId: string,
451
- field: TField,
452
- value: MockedChatScriptedMessage[TField],
453
- ): MockedChatPreset {
454
- return {
455
- ...previousDraft,
456
- messages: previousDraft.messages.map((message) => {
457
- if (message.id !== messageId) {
458
- return message;
459
- }
460
-
461
- return {
462
- ...message,
463
- [field]: value,
464
- };
465
- }),
466
- };
467
- }
468
-
469
- /**
470
- * Removes one scripted message.
471
- *
472
- * @private function of <MockedChatsEditorClient/>
473
- */
474
- function createDraftWithRemovedMessage(previousDraft: MockedChatPreset, messageId: string): MockedChatPreset {
475
- return {
476
- ...previousDraft,
477
- messages: previousDraft.messages.filter((message) => message.id !== messageId),
478
- };
479
- }
480
-
481
- /**
482
- * Applies one settings patch to the draft.
483
- *
484
- * @private function of <MockedChatsEditorClient/>
485
- */
486
- function createDraftWithUpdatedSettings(
487
- previousDraft: MockedChatPreset,
488
- settingsPatch: Partial<MockedChatSettings>,
489
- ): MockedChatPreset {
490
- return {
491
- ...previousDraft,
492
- settings: {
493
- ...previousDraft.settings,
494
- ...settingsPatch,
495
- },
496
- };
497
- }
498
-
499
89
  /**
500
90
  * Manages mocked-chat editor state, persistence, and draft mutations.
501
91
  *