@promptbook/cli 0.114.0-4 → 0.114.0-6

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 (329) hide show
  1. package/README.md +3 -3
  2. package/agents/default/developer.book +1 -0
  3. package/apps/agents-server/next.config.ts +22 -0
  4. package/apps/agents-server/package.json +6 -6
  5. package/apps/agents-server/scripts/build-agents-server.js +43 -7
  6. package/apps/agents-server/scripts/build-e2e.js +12 -2
  7. package/apps/agents-server/scripts/generate-reserved-paths/generate-reserved-paths.ts +30 -16
  8. package/apps/agents-server/scripts/kill-port.js +163 -0
  9. package/apps/agents-server/scripts/run-e2e-tests.js +21 -8
  10. package/apps/agents-server/scripts/run-npm.js +81 -5
  11. package/apps/agents-server/src/app/actions.ts +3 -0
  12. package/apps/agents-server/src/app/admin/email-server/page.tsx +17 -18
  13. package/apps/agents-server/src/app/admin/task-manager/TaskManagerTaskRow.tsx +2 -0
  14. package/apps/agents-server/src/app/admin/task-manager/[taskId]/TaskManagerTaskDetailClient.tsx +2 -0
  15. package/apps/agents-server/src/app/admin/task-manager/taskManagerTaskPresentation.tsx +23 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +7 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/api/timeouts/[timeoutId]/route.ts +10 -153
  18. package/apps/agents-server/src/app/agents/[agentName]/api/timeouts/route.ts +9 -4
  19. package/apps/agents-server/src/app/agents/[agentName]/api/user-chats/[chatId]/route.ts +3 -0
  20. package/apps/agents-server/src/app/agents/[agentName]/api/user-chats/[chatId]/stream/route.ts +2 -0
  21. package/apps/agents-server/src/app/agents/[agentName]/api/user-chats/resolveUserChatScope.ts +8 -1
  22. package/apps/agents-server/src/app/agents/[agentName]/api/user-chats/route.ts +15 -7
  23. package/apps/agents-server/src/app/agents/[agentName]/book/useBookEditorSaving.ts +18 -28
  24. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryClient.tsx +19 -1
  25. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatSidebarDefault.tsx +17 -5
  26. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatNotice.tsx +23 -0
  27. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatPlannedMessages.tsx +153 -0
  28. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatPanel.tsx +6 -0
  29. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +13 -0
  30. package/apps/agents-server/src/app/agents/[agentName]/chat/ExternalUserChatAdminActions.tsx +51 -3
  31. package/apps/agents-server/src/app/agents/[agentName]/chat/TeamMemberFrozenChatPrimaryAgentLink.tsx +31 -0
  32. package/apps/agents-server/src/app/agents/[agentName]/chat/useAgentChatSidebarState.ts +26 -2
  33. package/apps/agents-server/src/app/agents/[agentName]/goal/page.tsx +35 -0
  34. package/apps/agents-server/src/app/agents/[agentName]/projects/[projectName]/page.tsx +2 -2
  35. package/apps/agents-server/src/app/api/admin/dns-records/cloudflare/route.ts +26 -16
  36. package/apps/agents-server/src/app/api/emails/incoming/stalwart/route.ts +9 -2
  37. package/apps/agents-server/src/app/superadmin/servers/ServersRegistryTable.tsx +31 -39
  38. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +10 -3
  39. package/apps/agents-server/src/components/AgentProjects/AgentProjectIcon.tsx +137 -0
  40. package/apps/agents-server/src/components/AgentProjects/AgentProjectItem.tsx +26 -10
  41. package/apps/agents-server/src/components/CloudflareDnsWizard/CloudflareDnsApiTokenImportStep.tsx +5 -6
  42. package/apps/agents-server/src/components/CloudflareDnsWizard/CloudflareDnsCheckStep.tsx +6 -5
  43. package/apps/agents-server/src/components/CloudflareDnsWizard/CloudflareDnsManualStep.tsx +10 -14
  44. package/apps/agents-server/src/components/CloudflareDnsWizard/CloudflareDnsWizard.tsx +11 -20
  45. package/apps/agents-server/src/components/CloudflareDnsWizard/useCloudflareDnsRecordImport.ts +5 -6
  46. package/apps/agents-server/src/components/DnsRecordsInstructions/DnsRecordsInstructions.tsx +91 -57
  47. package/apps/agents-server/src/components/DnsRecordsInstructions/DnsRecordsSectionPanel.tsx +63 -0
  48. package/apps/agents-server/src/components/DnsRecordsInstructions/DnsRecordsSectionVariantTabs.tsx +67 -0
  49. package/apps/agents-server/src/components/DnsRecordsInstructions/DnsRecordsTable.tsx +40 -0
  50. package/apps/agents-server/src/components/Header/buildActiveAgentViewItems.ts +5 -4
  51. package/apps/agents-server/src/components/Header/createAgentViewLabel.tsx +4 -4
  52. package/apps/agents-server/src/components/Header/resolveActiveAgentNavigation.ts +2 -2
  53. package/apps/agents-server/src/components/Homepage/useAgentsListImportExportState.ts +22 -10
  54. package/apps/agents-server/src/components/_utils/generateMetaTxt.ts +1 -1
  55. package/apps/agents-server/src/database/migratePrefix.ts +13 -12
  56. package/apps/agents-server/src/database/migrations/2026-08-0100-agent-goal-chat-source.sql +10 -0
  57. package/apps/agents-server/src/generated/reservedPaths.ts +42 -42
  58. package/apps/agents-server/src/languages/ServerTranslationKeys.ts +9 -1
  59. package/apps/agents-server/src/languages/translations/czech.yaml +9 -1
  60. package/apps/agents-server/src/languages/translations/english.yaml +9 -1
  61. package/apps/agents-server/src/message-providers/email/stalwart/parseInboundStalwartEmail.ts +17 -2
  62. package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatConstants.ts +9 -0
  63. package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatIdentity.ts +28 -0
  64. package/apps/agents-server/src/utils/agentGoalChat/appendAgentGoalChatNote.ts +43 -0
  65. package/apps/agents-server/src/utils/agentGoalChat/canAccessAgentGoalChat.ts +14 -0
  66. package/apps/agents-server/src/utils/agentGoalChat/createAgentGoalChatNoteContent.ts +69 -0
  67. package/apps/agents-server/src/utils/agentGoalChat/ensureAgentGoalChat.ts +66 -0
  68. package/apps/agents-server/src/utils/agentGoalChat/prependAgentGoalChatSummarySeed.ts +40 -0
  69. package/apps/agents-server/src/utils/agentGoalChat/recordAgentGoalChatLifecycleNote.ts +36 -0
  70. package/apps/agents-server/src/utils/agentGoalChat/resolveAgentGoalChatOwnerUserId.ts +104 -0
  71. package/apps/agents-server/src/utils/agentGoalChat/scheduleAgentGoalChatModifiedNote.ts +82 -0
  72. package/apps/agents-server/src/utils/agentGoalChat.ts +19 -0
  73. package/apps/agents-server/src/utils/agentProjects/AgentProjectInfo.ts +10 -1
  74. package/apps/agents-server/src/utils/agentProjects/AgentProjectReferenceInfo.ts +5 -2
  75. package/apps/agents-server/src/utils/agentProjects/agentProjectFileNames.ts +21 -0
  76. package/apps/agents-server/src/utils/agentProjects/agentProjectHrefs.ts +20 -11
  77. package/apps/agents-server/src/utils/agentProjects/agentProjectsPaths.ts +15 -5
  78. package/apps/agents-server/src/utils/agentProjects/createAgentProjectInitials.ts +36 -0
  79. package/apps/agents-server/src/utils/agentProjects/createAgentProjectMarkdownReferences.ts +10 -9
  80. package/apps/agents-server/src/utils/agentProjects/createAgentProjectsDnsRecordsSection.ts +113 -0
  81. package/apps/agents-server/src/utils/agentProjects/createStaticAgentProjectServer.ts +2 -6
  82. package/apps/agents-server/src/utils/agentProjects/humanizeAgentProjectName.ts +25 -0
  83. package/apps/agents-server/src/utils/agentProjects/listAgentProjectChatReferences.ts +10 -3
  84. package/apps/agents-server/src/utils/agentProjects/parseAgentProjectIndexHtml.ts +167 -0
  85. package/apps/agents-server/src/utils/agentProjects/readAgentProjectIndexHtmlProfile.ts +24 -0
  86. package/apps/agents-server/src/utils/agentProjects/readAgentProjectReadme.ts +3 -53
  87. package/apps/agents-server/src/utils/agentProjects/readAgentProjectRootTextFile.ts +73 -0
  88. package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectFaviconRelativePath.ts +108 -0
  89. package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectInfo.ts +12 -3
  90. package/apps/agents-server/src/utils/agentProjects/{resolveAgentProjectReadmeProfile.ts → resolveAgentProjectProfile.ts} +33 -33
  91. package/apps/agents-server/src/utils/agentProjects/resolveAgentProjectPublicUrls.ts +34 -0
  92. package/apps/agents-server/src/utils/bookLanguageDocumentation/createBookLanguageDocumentationPdfResponse.ts +19 -17
  93. package/apps/agents-server/src/utils/chatTasksAdmin.ts +9 -0
  94. package/apps/agents-server/src/utils/dnsRecords/DnsRecordInstruction.ts +20 -0
  95. package/apps/agents-server/src/utils/dnsRecords/DnsRecordsSection.ts +77 -0
  96. package/apps/agents-server/src/utils/dnsRecords/createServerDnsRecordsSections.ts +58 -0
  97. package/apps/agents-server/src/utils/dnsRecords/createServerDomainDnsRecordsSection.ts +48 -0
  98. package/apps/agents-server/src/utils/dnsRecords/dnsRecordGroups.ts +52 -0
  99. package/apps/agents-server/src/utils/dnsRecords/resolveDnsRecordBatchPlan.ts +47 -1
  100. package/apps/agents-server/src/utils/getAdminChatTasksResponse/getAdminChatTasks/adminChatTaskSqlQuery.ts +41 -36
  101. package/apps/agents-server/src/utils/getAdminChatTasksResponse/getAdminChatTasks/mapAdminChatTaskFallbackRows.ts +3 -0
  102. package/apps/agents-server/src/utils/getAdminChatTasksResponse/getAdminChatTasks/mapAdminChatTaskSqlRows.ts +2 -0
  103. package/apps/agents-server/src/utils/localChatRunner/parseLocalTeamConversations.ts +281 -0
  104. package/apps/agents-server/src/utils/localChatRunner/persistLocalTeamConversations.ts +71 -0
  105. package/apps/agents-server/src/utils/localChatRunner/prepareLocalTeamConversationWorkspace.ts +233 -0
  106. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +37 -6
  107. package/apps/agents-server/src/utils/serverManagement/createManagedServer/insertManagedServerRegistryRow.ts +2 -2
  108. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerCoreAgents.ts +7 -6
  109. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerDefaultAgents.ts +5 -4
  110. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerMetadata.ts +3 -2
  111. package/apps/agents-server/src/utils/serverManagement/createManagedServer/seedServerUsers.ts +3 -2
  112. package/apps/agents-server/src/utils/serverManagement/deleteManagedServer.ts +2 -2
  113. package/apps/agents-server/src/utils/stalwart/createEmailDnsRecordsSection.ts +53 -0
  114. package/apps/agents-server/src/utils/userChat/UserChatRecord.ts +13 -0
  115. package/apps/agents-server/src/utils/userChat/UserChatSource.ts +14 -0
  116. package/apps/agents-server/src/utils/userChat/createUserChatSummary.ts +10 -2
  117. package/apps/agents-server/src/utils/userChat/finalizeUserChatJob.ts +3 -2
  118. package/apps/agents-server/src/utils/userChat/getUserChat.ts +16 -1
  119. package/apps/agents-server/src/utils/userChat/getUserChatForJobRunner.ts +31 -0
  120. package/apps/agents-server/src/utils/userChat/listUserChats.ts +113 -110
  121. package/apps/agents-server/src/utils/userChat/persistFrozenUserChat.ts +21 -6
  122. package/apps/agents-server/src/utils/userChat/runImmediateUserChatAnswer.ts +2 -6
  123. package/apps/agents-server/src/utils/userChat/runUserChatJob.ts +2 -6
  124. package/apps/agents-server/src/utils/userChat/teamMemberUserChatContext.ts +63 -0
  125. package/apps/agents-server/src/utils/userChat.ts +5 -1
  126. package/apps/agents-server/src/utils/userChatClient/cancelAgentUserTimeout.ts +2 -2
  127. package/apps/agents-server/src/utils/userChatClient/fetchAgentUserTimeouts.ts +2 -2
  128. package/apps/agents-server/src/utils/userChatClient.ts +9 -31
  129. package/apps/agents-server/src/utils/userChatTimeout/UserChatTimeoutRecord.ts +10 -2
  130. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/claimNextDueUserChatTimeout.ts +28 -25
  131. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/getAgentScopedUserChatTimeout.ts +8 -4
  132. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/listAgentUserChatTimeouts.ts +4 -1
  133. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/recoverExpiredRunningUserChatTimeouts.ts +3 -2
  134. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutWorker.ts +53 -0
  135. package/esm/index.es.js +1801 -474
  136. package/esm/index.es.js.map +1 -1
  137. package/esm/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +7 -1
  138. package/esm/scripts/run-agent-messages/messages/buildAgentTeamPromptSection.d.ts +12 -0
  139. package/esm/scripts/run-agent-messages/messages/finalizeAgentTeamConversationWorkspace.d.ts +16 -0
  140. package/esm/scripts/run-agent-messages/messages/loadAgentTeamConversationWorkspace.d.ts +6 -0
  141. package/esm/scripts/run-codex-prompts/common/createCoderRunStepTracker.d.ts +48 -0
  142. package/esm/scripts/run-codex-prompts/common/normalizeLineEndingsInChangedFiles.d.ts +2 -3
  143. package/esm/scripts/run-codex-prompts/git/coderCommitScope.d.ts +31 -0
  144. package/esm/scripts/run-codex-prompts/git/coderGitSync.d.ts +15 -2
  145. package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +9 -3
  146. package/esm/scripts/run-codex-prompts/git/workingTreeChanges.d.ts +40 -0
  147. package/esm/scripts/run-codex-prompts/prompts/buildPromptStatusDetails.d.ts +43 -0
  148. package/esm/scripts/run-codex-prompts/prompts/formatCoderRunSteps.d.ts +6 -3
  149. package/esm/scripts/run-codex-prompts/prompts/isPromptSectionUnfinished.d.ts +8 -0
  150. package/esm/scripts/run-codex-prompts/prompts/markPromptDone.d.ts +1 -1
  151. package/esm/scripts/run-codex-prompts/prompts/markPromptInProgress.d.ts +27 -0
  152. package/esm/scripts/run-codex-prompts/prompts/resolvePromptStatusLine.d.ts +19 -0
  153. package/esm/scripts/run-codex-prompts/prompts/writePromptStatusLine.d.ts +9 -0
  154. package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +1 -1
  155. package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  156. package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  157. package/esm/scripts/run-codex-prompts/testing/runPromptWithTestFeedback.d.ts +6 -0
  158. package/esm/scripts/run-codex-prompts/ui/buildCoderRunAgentVisual.d.ts +5 -5
  159. package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiTerminalFrameUpdate.d.ts +27 -0
  160. package/esm/scripts/verify-prompts/$orderPromptFiles.d.ts +9 -0
  161. package/esm/scripts/verify-prompts/VerifyPromptsOrder.d.ts +26 -0
  162. package/esm/scripts/verify-prompts/verify-prompts.d.ts +3 -2
  163. package/esm/src/avatars/renderAvatarVisualTerminalText.d.ts +80 -0
  164. package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +54 -0
  165. package/esm/src/book-3.0/AgentTeamConversationWorkspace.d.ts +85 -0
  166. package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +3 -2
  167. package/esm/src/book-components/Chat/utils/renderMarkdown.d.ts +5 -3
  168. package/esm/src/cli/cli-commands/coder/boilerplateCount.d.ts +1 -1
  169. package/esm/src/cli/cli-commands/coder/generate-boilerplates.d.ts +1 -1
  170. package/esm/src/cli/cli-commands/coder/verify.d.ts +1 -1
  171. package/{umd/src/cli/cli-commands/common/harness/$askForHarnessInstallationApproval.d.ts → esm/src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.d.ts} +2 -2
  172. package/{umd/src/cli/cli-commands/common/harness/$resolveLatestHarnessVersion.d.ts → esm/src/cli/cli-commands/common/npm/$resolveLatestNpmPackageVersion.d.ts} +2 -3
  173. package/esm/src/cli/cli-commands/common/npm/extractNpmPackageVersionFromOutput.d.ts +12 -0
  174. package/esm/src/cli/cli-commands/common/npm/isNpmPackageVersionOutdated.d.ts +9 -0
  175. package/esm/src/cli/cli-commands/common/promptbook-cli/$checkPromptbookCliInstallations.d.ts +9 -0
  176. package/esm/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.d.ts +14 -0
  177. package/esm/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.test.d.ts +1 -0
  178. package/esm/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.d.ts +12 -0
  179. package/esm/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.test.d.ts +1 -0
  180. package/esm/src/cli/cli-commands/common/promptbook-cli/$updatePromptbookCliInstallation.d.ts +10 -0
  181. package/esm/src/cli/cli-commands/common/promptbook-cli/PromptbookCliInstallation.d.ts +39 -0
  182. package/esm/src/cli/cli-commands/common/promptbook-cli/PromptbookCliInstallationStatus.d.ts +26 -0
  183. package/esm/src/cli/cli-commands/common/promptbook-cli/buildPromptbookCliInstallCommand.d.ts +7 -0
  184. package/esm/src/cli/cli-commands/common/promptbook-cli/buildPromptbookCliInstallCommand.test.d.ts +1 -0
  185. package/esm/src/cli/cli-commands/common/promptbook-cli/formatPromptbookCliInstallationWarning.d.ts +7 -0
  186. package/esm/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.d.ts +3 -3
  187. package/esm/src/utils/agents/terminalAgentAvatarVisual.d.ts +5 -2
  188. package/esm/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +6 -0
  189. package/esm/src/utils/ascii-art/createAnsiColorCode.d.ts +46 -0
  190. package/esm/src/utils/misc/debounce.d.ts +4 -2
  191. package/esm/src/utils/misc/debounce.test.d.ts +1 -0
  192. package/esm/src/version.d.ts +1 -1
  193. package/package.json +1 -1
  194. package/src/avatars/renderAvatarVisualTerminalText.ts +249 -0
  195. package/src/avatars/types/AvatarVisualDefinition.ts +60 -0
  196. package/src/avatars/visuals/asciiOctopusAvatarVisual.ts +144 -22
  197. package/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.ts +4 -4
  198. package/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.ts +1 -4
  199. package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +4 -17
  200. package/src/book-3.0/AgentTeamConversationWorkspace.ts +172 -0
  201. package/src/book-components/BookEditor/useBookEditorMonacoStyles.ts +56 -55
  202. package/src/book-components/Chat/Chat/Chat.module.css +1 -8
  203. package/src/book-components/Chat/Chat/ChatMessageMap.tsx +8 -4
  204. package/src/book-components/Chat/Chat/ChatProps.tsx +3 -2
  205. package/src/book-components/Chat/save/react/exports/chat-preview-2025-10-13 (1).jsx +95 -5
  206. package/src/book-components/Chat/utils/renderMarkdown.ts +306 -87
  207. package/src/cli/cli-commands/coder/add.ts +3 -3
  208. package/src/cli/cli-commands/coder/boilerplateCount.ts +1 -1
  209. package/src/cli/cli-commands/coder/generate-boilerplates.ts +27 -27
  210. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +5 -4
  211. package/src/cli/cli-commands/coder/init.ts +3 -3
  212. package/src/cli/cli-commands/coder/run.ts +10 -2
  213. package/src/cli/cli-commands/coder/verify.ts +29 -5
  214. package/src/cli/cli-commands/common/coderGitSyncCliOptions.ts +6 -2
  215. package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +2 -2
  216. package/src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts +4 -4
  217. package/src/cli/cli-commands/common/harness/$resolveInstalledHarnessVersion.ts +2 -2
  218. package/src/cli/cli-commands/common/{harness/$askForHarnessInstallationApproval.ts → npm/$askForNpmPackageInstallationApproval.ts} +3 -3
  219. package/src/cli/cli-commands/common/npm/$resolveLatestNpmPackageVersion.ts +49 -0
  220. package/src/cli/cli-commands/common/npm/extractNpmPackageVersionFromOutput.ts +25 -0
  221. package/src/cli/cli-commands/common/{harness/isHarnessVersionOutdated.ts → npm/isNpmPackageVersionOutdated.ts} +6 -4
  222. package/src/cli/cli-commands/common/projectInitialization.ts +10 -1
  223. package/src/cli/cli-commands/common/promptbook-cli/$checkPromptbookCliInstallations.ts +73 -0
  224. package/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.ts +94 -0
  225. package/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.ts +223 -0
  226. package/src/cli/cli-commands/common/promptbook-cli/$updatePromptbookCliInstallation.ts +53 -0
  227. package/src/cli/cli-commands/common/promptbook-cli/PromptbookCliInstallation.ts +46 -0
  228. package/src/cli/cli-commands/common/promptbook-cli/PromptbookCliInstallationStatus.ts +32 -0
  229. package/src/cli/cli-commands/common/promptbook-cli/buildPromptbookCliInstallCommand.ts +22 -0
  230. package/src/cli/cli-commands/common/promptbook-cli/formatPromptbookCliInstallationWarning.ts +47 -0
  231. package/src/commands/FORMAT/formatCommandParser.ts +2 -2
  232. package/src/llm-providers/openai/utils/buildToolInvocationScript.ts +21 -18
  233. package/src/other/templates/getTemplatesPipelineCollection.ts +813 -768
  234. package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +80 -27
  235. package/src/utils/agents/terminalAgentAvatarVisual.ts +31 -3
  236. package/src/utils/ascii-art/convertImageDataToAsciiArt.ts +9 -109
  237. package/src/utils/ascii-art/createAnsiColorCode.ts +132 -0
  238. package/src/utils/misc/debounce.ts +26 -5
  239. package/src/version.ts +2 -2
  240. package/src/versions.txt +2 -0
  241. package/umd/index.umd.js +1800 -473
  242. package/umd/index.umd.js.map +1 -1
  243. package/umd/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +7 -1
  244. package/umd/scripts/run-agent-messages/messages/buildAgentTeamPromptSection.d.ts +12 -0
  245. package/umd/scripts/run-agent-messages/messages/finalizeAgentTeamConversationWorkspace.d.ts +16 -0
  246. package/umd/scripts/run-agent-messages/messages/loadAgentTeamConversationWorkspace.d.ts +6 -0
  247. package/umd/scripts/run-codex-prompts/common/createCoderRunStepTracker.d.ts +48 -0
  248. package/umd/scripts/run-codex-prompts/common/normalizeLineEndingsInChangedFiles.d.ts +2 -3
  249. package/umd/scripts/run-codex-prompts/git/coderCommitScope.d.ts +31 -0
  250. package/umd/scripts/run-codex-prompts/git/coderGitSync.d.ts +15 -2
  251. package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +9 -3
  252. package/umd/scripts/run-codex-prompts/git/workingTreeChanges.d.ts +40 -0
  253. package/umd/scripts/run-codex-prompts/prompts/buildPromptStatusDetails.d.ts +43 -0
  254. package/umd/scripts/run-codex-prompts/prompts/formatCoderRunSteps.d.ts +6 -3
  255. package/umd/scripts/run-codex-prompts/prompts/isPromptSectionUnfinished.d.ts +8 -0
  256. package/umd/scripts/run-codex-prompts/prompts/markPromptDone.d.ts +1 -1
  257. package/umd/scripts/run-codex-prompts/prompts/markPromptInProgress.d.ts +27 -0
  258. package/umd/scripts/run-codex-prompts/prompts/resolvePromptStatusLine.d.ts +19 -0
  259. package/umd/scripts/run-codex-prompts/prompts/writePromptStatusLine.d.ts +9 -0
  260. package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +1 -1
  261. package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  262. package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  263. package/umd/scripts/run-codex-prompts/testing/runPromptWithTestFeedback.d.ts +6 -0
  264. package/umd/scripts/run-codex-prompts/ui/buildCoderRunAgentVisual.d.ts +5 -5
  265. package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiTerminalFrameUpdate.d.ts +27 -0
  266. package/umd/scripts/verify-prompts/$orderPromptFiles.d.ts +9 -0
  267. package/umd/scripts/verify-prompts/VerifyPromptsOrder.d.ts +26 -0
  268. package/umd/scripts/verify-prompts/verify-prompts.d.ts +3 -2
  269. package/umd/src/avatars/renderAvatarVisualTerminalText.d.ts +80 -0
  270. package/umd/src/avatars/renderAvatarVisualTerminalText.test.d.ts +1 -0
  271. package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +54 -0
  272. package/umd/src/book-3.0/AgentTeamConversationWorkspace.d.ts +85 -0
  273. package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +3 -2
  274. package/umd/src/book-components/Chat/utils/renderMarkdown.d.ts +5 -3
  275. package/umd/src/cli/cli-commands/coder/boilerplateCount.d.ts +1 -1
  276. package/umd/src/cli/cli-commands/coder/generate-boilerplates.d.ts +1 -1
  277. package/umd/src/cli/cli-commands/coder/verify.d.ts +1 -1
  278. package/{esm/src/cli/cli-commands/common/harness/$askForHarnessInstallationApproval.d.ts → umd/src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.d.ts} +2 -2
  279. package/{esm/src/cli/cli-commands/common/harness/$resolveLatestHarnessVersion.d.ts → umd/src/cli/cli-commands/common/npm/$resolveLatestNpmPackageVersion.d.ts} +2 -3
  280. package/umd/src/cli/cli-commands/common/npm/$resolveLatestNpmPackageVersion.test.d.ts +1 -0
  281. package/umd/src/cli/cli-commands/common/npm/extractNpmPackageVersionFromOutput.d.ts +12 -0
  282. package/umd/src/cli/cli-commands/common/npm/extractNpmPackageVersionFromOutput.test.d.ts +1 -0
  283. package/umd/src/cli/cli-commands/common/npm/isNpmPackageVersionOutdated.d.ts +9 -0
  284. package/umd/src/cli/cli-commands/common/npm/isNpmPackageVersionOutdated.test.d.ts +1 -0
  285. package/umd/src/cli/cli-commands/common/promptbook-cli/$checkPromptbookCliInstallations.d.ts +9 -0
  286. package/umd/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.d.ts +14 -0
  287. package/umd/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.test.d.ts +1 -0
  288. package/umd/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.d.ts +12 -0
  289. package/umd/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.test.d.ts +1 -0
  290. package/umd/src/cli/cli-commands/common/promptbook-cli/$updatePromptbookCliInstallation.d.ts +10 -0
  291. package/umd/src/cli/cli-commands/common/promptbook-cli/PromptbookCliInstallation.d.ts +39 -0
  292. package/umd/src/cli/cli-commands/common/promptbook-cli/PromptbookCliInstallationStatus.d.ts +26 -0
  293. package/umd/src/cli/cli-commands/common/promptbook-cli/buildPromptbookCliInstallCommand.d.ts +7 -0
  294. package/umd/src/cli/cli-commands/common/promptbook-cli/buildPromptbookCliInstallCommand.test.d.ts +1 -0
  295. package/umd/src/cli/cli-commands/common/promptbook-cli/formatPromptbookCliInstallationWarning.d.ts +7 -0
  296. package/umd/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.d.ts +3 -3
  297. package/umd/src/utils/agents/terminalAgentAvatarVisual.d.ts +5 -2
  298. package/umd/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +6 -0
  299. package/umd/src/utils/ascii-art/createAnsiColorCode.d.ts +46 -0
  300. package/umd/src/utils/misc/debounce.d.ts +4 -2
  301. package/umd/src/utils/misc/debounce.test.d.ts +1 -0
  302. package/umd/src/version.d.ts +1 -1
  303. package/apps/agents-server/scripts/ignore-kill-eperm.js +0 -31
  304. package/apps/agents-server/src/app/agents/[agentName]/api/timeouts/actions/route.ts +0 -103
  305. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsClient.tsx +0 -43
  306. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsEditDialog.tsx +0 -98
  307. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsFiltersCard.tsx +0 -75
  308. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsHeader.tsx +0 -53
  309. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsSummaryMetrics.tsx +0 -70
  310. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsTableCard.tsx +0 -58
  311. package/apps/agents-server/src/app/agents/[agentName]/timeouts/AgentTimeoutsTableRow.tsx +0 -242
  312. package/apps/agents-server/src/app/agents/[agentName]/timeouts/loading.tsx +0 -15
  313. package/apps/agents-server/src/app/agents/[agentName]/timeouts/page.tsx +0 -28
  314. package/apps/agents-server/src/app/agents/[agentName]/timeouts/useAgentTimeoutsClientState.ts +0 -769
  315. package/apps/agents-server/src/components/AgentProjectDnsInstructions/AgentProjectDnsInstructions.tsx +0 -182
  316. package/apps/agents-server/src/utils/userChatClient/runAgentUserTimeoutBulkAction.ts +0 -24
  317. package/apps/agents-server/src/utils/userChatClient/updateAgentUserTimeout.ts +0 -25
  318. package/esm/scripts/run-codex-prompts/prompts/replacePromptTodoStatusLine.d.ts +0 -7
  319. package/esm/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.d.ts +0 -11
  320. package/esm/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.d.ts +0 -9
  321. package/src/cli/cli-commands/common/harness/$resolveLatestHarnessVersion.ts +0 -34
  322. package/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.ts +0 -28
  323. package/umd/scripts/run-codex-prompts/prompts/replacePromptTodoStatusLine.d.ts +0 -7
  324. package/umd/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.d.ts +0 -11
  325. package/umd/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.d.ts +0 -9
  326. /package/esm/src/{cli/cli-commands/common/harness/extractHarnessVersionFromOutput.test.d.ts → avatars/renderAvatarVisualTerminalText.test.d.ts} +0 -0
  327. /package/esm/src/cli/cli-commands/common/{harness/isHarnessVersionOutdated.test.d.ts → npm/$resolveLatestNpmPackageVersion.test.d.ts} +0 -0
  328. /package/{umd/src/cli/cli-commands/common/harness/extractHarnessVersionFromOutput.test.d.ts → esm/src/cli/cli-commands/common/npm/extractNpmPackageVersionFromOutput.test.d.ts} +0 -0
  329. /package/{umd/src/cli/cli-commands/common/harness/isHarnessVersionOutdated.test.d.ts → esm/src/cli/cli-commands/common/npm/isNpmPackageVersionOutdated.test.d.ts} +0 -0
@@ -2,8 +2,9 @@ import { NextResponse } from 'next/server';
2
2
  import { spaceTrim } from 'spacetrim';
3
3
  import { NotFoundError } from '../../../../../../../../src/errors/NotFoundError';
4
4
  import { applyCloudflareDnsRecordInstructions } from '../../../../../utils/cloudflare/applyCloudflareDnsRecordInstructions';
5
- import type { DnsRecordInstruction, DnsRecordSelection } from '../../../../../utils/dnsRecords/DnsRecordInstruction';
6
- import { resolveDnsRecordBatchPlan } from '../../../../../utils/dnsRecords/resolveDnsRecordBatchPlan';
5
+ import type { DnsRecordGroup } from '../../../../../utils/dnsRecords/DnsRecordInstruction';
6
+ import { countDnsRecordGroupRecords } from '../../../../../utils/dnsRecords/dnsRecordGroups';
7
+ import { resolveDnsRecordBatchPlanForGroups } from '../../../../../utils/dnsRecords/resolveDnsRecordBatchPlan';
7
8
  import { isUserAdmin } from '../../../../../utils/isUserAdmin';
8
9
  import { isUserGlobalAdmin } from '../../../../../utils/isUserGlobalAdmin';
9
10
 
@@ -22,14 +23,9 @@ type CloudflareDnsWizardRequestBody = {
22
23
  readonly domain?: string;
23
24
 
24
25
  /**
25
- * Whether all shown records or one shown alternative has to be configured.
26
+ * Record groups shown in the DNS manual, each one with its own all-or-one rule.
26
27
  */
27
- readonly recordSelection?: DnsRecordSelection;
28
-
29
- /**
30
- * DNS records shown in the DNS manual.
31
- */
32
- readonly records?: ReadonlyArray<DnsRecordInstruction>;
28
+ readonly recordGroups?: ReadonlyArray<DnsRecordGroup>;
33
29
  };
34
30
 
35
31
  /**
@@ -45,13 +41,13 @@ export async function POST(request: Request) {
45
41
 
46
42
  const body = ((await request.json().catch(() => null)) || {}) as CloudflareDnsWizardRequestBody;
47
43
  const domain = (body.domain || '').trim();
48
- const records = body.records || [];
44
+ const recordGroups = normalizeCloudflareDnsWizardRecordGroups(body.recordGroups);
49
45
 
50
- if (!domain || records.length === 0) {
46
+ if (!domain || countDnsRecordGroupRecords(recordGroups) === 0) {
51
47
  return NextResponse.json(
52
48
  {
53
49
  error: spaceTrim(`
54
- Both \`domain\` and \`records\` are required to import DNS records into Cloudflare.
50
+ Both \`domain\` and \`recordGroups\` are required to import DNS records into Cloudflare.
55
51
  `),
56
52
  },
57
53
  { status: 400 },
@@ -79,10 +75,7 @@ export async function POST(request: Request) {
79
75
 
80
76
  // Note: The batch plan is resolved again on the server, so that placeholder values and record alternatives can
81
77
  // never be written into Cloudflare even when the browser sends them.
82
- const { applicableRecords } = resolveDnsRecordBatchPlan({
83
- records,
84
- recordSelection: body.recordSelection === 'one' ? 'one' : 'all',
85
- });
78
+ const { applicableRecords } = resolveDnsRecordBatchPlanForGroups(recordGroups);
86
79
 
87
80
  if (applicableRecords.length === 0) {
88
81
  return NextResponse.json(
@@ -114,3 +107,20 @@ export async function POST(request: Request) {
114
107
  );
115
108
  }
116
109
  }
110
+
111
+ /**
112
+ * Normalizes the record groups sent by the browser into trustworthy server-side groups.
113
+ *
114
+ * @param recordGroups - Record groups of the request body.
115
+ * @returns Record groups whose all-or-one rule is always one of the supported values.
116
+ *
117
+ * @private function of `POST`
118
+ */
119
+ function normalizeCloudflareDnsWizardRecordGroups(
120
+ recordGroups: ReadonlyArray<DnsRecordGroup> | undefined,
121
+ ): ReadonlyArray<DnsRecordGroup> {
122
+ return (recordGroups || []).map((recordGroup) => ({
123
+ recordSelection: recordGroup.recordSelection === 'one' ? 'one' : 'all',
124
+ records: recordGroup.records || [],
125
+ }));
126
+ }
@@ -5,6 +5,7 @@ import { ParseError } from '../../../../../../../../src/errors/ParseError';
5
5
  import { spaceTrim } from '../../../../../../../../src/utils/organization/spaceTrim';
6
6
  import type { StalwartMtaHookPayload } from '../../../../../message-providers/email/stalwart/StalwartMtaHookPayload';
7
7
  import { parseInboundStalwartEmail } from '../../../../../message-providers/email/stalwart/parseInboundStalwartEmail';
8
+ import { $provideServer } from '../../../../../tools/$provideServer';
8
9
  import { processInboundAgentEmail } from '../../../../../utils/email/processInboundAgentEmail';
9
10
  import { NextRequest, NextResponse } from 'next/server';
10
11
 
@@ -16,6 +17,12 @@ export async function POST(request: NextRequest) {
16
17
  verifyStalwartMtaHookAuthorization(request.headers.get('authorization'));
17
18
  const payload = (await request.json()) as StalwartMtaHookPayload;
18
19
  const parsedEmail = await parseInboundStalwartEmail(payload);
20
+
21
+ // Note: `request.nextUrl` describes the internal listener this process was reached on, so behind
22
+ // the VPS reverse proxy its hostname is `localhost` and never the mail domain. The server
23
+ // registry is the single source of truth which already decides the database namespace of
24
+ // this request, so the mail domain and the worker origin are taken from it as well.
25
+ const { publicUrl } = await $provideServer();
19
26
  const result = await processInboundAgentEmail({
20
27
  email: parsedEmail.email,
21
28
  envelope: {
@@ -23,8 +30,8 @@ export async function POST(request: NextRequest) {
23
30
  recipients: parsedEmail.envelopeRecipients,
24
31
  queueId: parsedEmail.queueId,
25
32
  },
26
- domain: request.nextUrl.hostname,
27
- origin: request.nextUrl.origin,
33
+ domain: publicUrl.hostname,
34
+ origin: publicUrl.origin,
28
35
  });
29
36
 
30
37
  return NextResponse.json({
@@ -2,10 +2,10 @@
2
2
 
3
3
  import { Fragment } from 'react';
4
4
  import { ArrowRightLeft, Bot, ExternalLink, Loader2, Mail, RefreshCcw, Save } from 'lucide-react';
5
- import { AgentProjectDnsInstructions } from '../../../components/AgentProjectDnsInstructions/AgentProjectDnsInstructions';
6
5
  import { DnsRecordsInstructions } from '../../../components/DnsRecordsInstructions/DnsRecordsInstructions';
7
6
  import { useServerLanguage } from '../../../components/ServerLanguage/ServerLanguageProvider';
8
7
  import type { ServerLanguageCode } from '../../../languages/ServerLanguageRegistry';
8
+ import { createServerDnsRecordsSections } from '../../../utils/dnsRecords/createServerDnsRecordsSections';
9
9
  import { formatServerLanguageHumanReadableDate } from '../../../utils/localization/formatServerLanguageHumanReadableDate';
10
10
  import { AdminSortableTableHeaderCell } from '../../admin/_components/AdminSortableTableHeaderCell';
11
11
  import { useAdminTableSorting } from '../../admin/_components/adminTableSorting';
@@ -244,6 +244,7 @@ function ServersRegistryTableRow(props: ServersRegistryTableRowProps) {
244
244
  const hasProjectDnsIssue = projectDomains.some((projectDomain) =>
245
245
  isManagedServerDnsDiagnosticIssue(projectDomain.dnsDiagnostic),
246
246
  );
247
+ const generatedProjectDomain = projectDomains.find((projectDomain) => !projectDomain.customDomain)?.domain ?? null;
247
248
  const columnCount = isStandaloneVps ? 6 : 8;
248
249
 
249
250
  return (
@@ -341,10 +342,10 @@ function ServersRegistryTableRow(props: ServersRegistryTableRowProps) {
341
342
  <a
342
343
  href={`https://${server.domain}/admin/email-server`}
343
344
  className={`${SECONDARY_BUTTON_CLASS_NAME} px-2 py-1 text-xs`}
344
- title={`MX, SPF, DKIM, and DMARC instructions for ${server.domain}`}
345
+ title={`Agent addresses and the generated DKIM zone of ${server.domain}`}
345
346
  >
346
347
  <Mail className="h-3.5 w-3.5" />
347
- Mail DNS
348
+ Email server
348
349
  </a>
349
350
  <button
350
351
  type="button"
@@ -390,57 +391,54 @@ function ServersRegistryTableRow(props: ServersRegistryTableRowProps) {
390
391
  </tr>
391
392
  <tr className="bg-sky-50/50">
392
393
  <td colSpan={columnCount} className="px-4 py-4">
393
- <ProjectDomainsPanel
394
- projectDomains={projectDomains}
395
- publicIpAddress={dnsDiagnostic?.publicIpAddress}
396
- serverDomain={server.domain}
397
- />
394
+ <ProjectDomainsPanel projectDomains={projectDomains} />
398
395
  </td>
399
396
  </tr>
400
- {hasDnsIssue && dnsDiagnostic ? (
401
- <tr className="bg-amber-50/70">
402
- <td colSpan={columnCount} className="px-4 py-4">
403
- <DnsRecordsInstructions
404
- description={dnsDiagnostic.summary}
405
- domain={server.domain}
406
- recordSelection="one"
407
- records={dnsDiagnostic.expectedRecords}
408
- providerGuides={dnsDiagnostic.providerGuides}
409
- resolvedAddresses={dnsDiagnostic.resolvedAddresses}
410
- title={
397
+ <tr className="bg-amber-50/70">
398
+ <td colSpan={columnCount} className="px-4 py-4">
399
+ <DnsRecordsInstructions
400
+ description="Everything this server needs at its DNS provider - its own domain, the generated project domains, and its email. Add all of them at once with the Cloudflare wizard below."
401
+ domain={server.domain}
402
+ providerGuides={dnsDiagnostic?.providerGuides}
403
+ sections={createServerDnsRecordsSections({
404
+ serverDomain: server.domain,
405
+ dnsDiagnostic,
406
+ isProjectDnsIssue: hasProjectDnsIssue,
407
+ projectDomain: generatedProjectDomain,
408
+ })}
409
+ title={
410
+ hasDnsIssue || hasProjectDnsIssue ? (
411
411
  <>
412
412
  DNS setup needs attention for <span className="font-mono">{server.domain}</span>
413
413
  </>
414
- }
415
- />
416
- </td>
417
- </tr>
418
- ) : null}
414
+ ) : (
415
+ <>
416
+ DNS setup for <span className="font-mono">{server.domain}</span>
417
+ </>
418
+ )
419
+ }
420
+ />
421
+ </td>
422
+ </tr>
419
423
  </>
420
424
  );
421
425
  }
422
426
 
423
427
  /**
424
- * Renders assigned project domains and preventive DNS guidance for one server.
428
+ * Renders the project domains assigned to one server.
429
+ *
430
+ * Their DNS setup intentionally lives in the one shared DNS manual of the server instead of in this listing.
425
431
  */
426
432
  function ProjectDomainsPanel({
427
- publicIpAddress,
428
433
  projectDomains,
429
- serverDomain,
430
434
  }: {
431
- readonly publicIpAddress: string | null | undefined;
432
435
  readonly projectDomains: NonNullable<ManagedServerRow['projectDomains']>;
433
- readonly serverDomain: string;
434
436
  }) {
435
437
  const projectDomainSorting = useAdminTableSorting<ProjectDomainRow, ProjectDomainsTableSortField>({
436
438
  rows: projectDomains,
437
439
  defaultSortBy: 'projectName',
438
440
  resolveSortValue: resolveProjectDomainSortValue,
439
441
  });
440
- const generatedProjectDomain = projectDomains.find((projectDomain) => !projectDomain.customDomain)?.domain ?? null;
441
- const hasProjectDnsIssue = projectDomains.some((projectDomain) =>
442
- isManagedServerDnsDiagnosticIssue(projectDomain.dnsDiagnostic),
443
- );
444
442
 
445
443
  return (
446
444
  <div className="space-y-3 rounded-lg border border-sky-200 bg-sky-50 px-4 py-4 text-sm text-sky-950">
@@ -535,12 +533,6 @@ function ProjectDomainsPanel({
535
533
  </table>
536
534
  </div>
537
535
  )}
538
- <AgentProjectDnsInstructions
539
- isDnsIssue={hasProjectDnsIssue}
540
- projectDomain={generatedProjectDomain}
541
- publicIpAddress={publicIpAddress}
542
- serverDomain={serverDomain}
543
- />
544
536
  </div>
545
537
  );
546
538
  }
@@ -1,4 +1,6 @@
1
1
  'use client';
2
+ import { spaceTrim } from 'spacetrim';
3
+
2
4
 
3
5
  import { colorToDataUrl } from '@promptbook-local/color';
4
6
  import { AgentBasicInformation, string_agent_permanent_id, string_url } from '@promptbook-local/types';
@@ -104,6 +106,13 @@ export function AgentProfile(props: AgentProfileProps) {
104
106
  // Dynamic Font Loading
105
107
  const fontString = meta.font;
106
108
  const primaryFontFamily = fontString ? (fontString.split(',')[0] || '').trim().replace(/['"]/g, '') : '';
109
+ const PRIMARY_FONT_IMPORT_STYLES = primaryFontFamily
110
+ ? spaceTrim(
111
+ (block) => `
112
+ @import url('https://fonts.googleapis.com/css2?family=${block(encodeURIComponent(primaryFontFamily))}:wght@400;600;700&display=swap');
113
+ `,
114
+ )
115
+ : '';
107
116
  let fontStyle: React.CSSProperties = {};
108
117
 
109
118
  if (fontString) {
@@ -120,9 +129,7 @@ export function AgentProfile(props: AgentProfileProps) {
120
129
  return (
121
130
  <>
122
131
  {primaryFontFamily && (
123
- <style jsx global>{`
124
- @import url('https://fonts.googleapis.com/css2?family=${encodeURIComponent(primaryFontFamily)}:wght@400;600;700&display=swap');
125
- `}</style>
132
+ <style jsx global>{PRIMARY_FONT_IMPORT_STYLES}</style>
126
133
  )}
127
134
 
128
135
  {/* Full-screen background with agent color */}
@@ -0,0 +1,137 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import type { AgentProjectReferenceInfo } from '../../utils/agentProjects/AgentProjectReferenceInfo';
5
+ import { buildAgentProjectFileHrefForServer } from '../../utils/agentProjects/agentProjectHrefs';
6
+ import { createAgentProjectInitials } from '../../utils/agentProjects/createAgentProjectInitials';
7
+
8
+ /**
9
+ * Sizes at which one project icon is shown.
10
+ */
11
+ export type AgentProjectIconSize = 'small' | 'card' | 'header';
12
+
13
+ /**
14
+ * Project fields required to render the icon of one project.
15
+ */
16
+ export type AgentProjectIconInfo = Pick<AgentProjectReferenceInfo, 'projectName' | 'faviconRelativePath'>;
17
+
18
+ /**
19
+ * Classes of the icon container, of the favicon and of the initials per icon size.
20
+ */
21
+ const AGENT_PROJECT_ICON_CLASS_NAMES_BY_SIZE: Record<
22
+ AgentProjectIconSize,
23
+ {
24
+ /**
25
+ * Classes of the icon container.
26
+ */
27
+ readonly container: string;
28
+
29
+ /**
30
+ * Classes of the rendered favicon.
31
+ */
32
+ readonly favicon: string;
33
+
34
+ /**
35
+ * Classes of the rendered initials.
36
+ */
37
+ readonly initials: string;
38
+ }
39
+ > = {
40
+ small: { container: 'h-5 w-5 rounded-md', favicon: 'p-0.5', initials: 'text-[0.5rem] tracking-tight' },
41
+ card: { container: 'h-11 w-11 rounded-lg', favicon: 'p-1.5', initials: 'text-sm' },
42
+ header: { container: 'h-9 w-9 rounded-lg', favicon: 'p-1', initials: 'text-xs' },
43
+ };
44
+
45
+ /**
46
+ * Props for one project icon.
47
+ */
48
+ type AgentProjectIconProps = {
49
+ /**
50
+ * Permanent id of the agent owning the project.
51
+ */
52
+ readonly agentPermanentId: string;
53
+
54
+ /**
55
+ * Project the icon belongs to.
56
+ */
57
+ readonly project: AgentProjectIconInfo;
58
+
59
+ /**
60
+ * Public domain of the server owning the project, when known.
61
+ */
62
+ readonly serverDomain?: string | null;
63
+
64
+ /**
65
+ * Public domain serving the current page, when known.
66
+ */
67
+ readonly currentServerDomain?: string | null;
68
+
69
+ /**
70
+ * Size at which the icon is shown.
71
+ */
72
+ readonly size: AgentProjectIconSize;
73
+
74
+ /**
75
+ * Optional CSS class overrides.
76
+ */
77
+ readonly className?: string;
78
+ };
79
+
80
+ /**
81
+ * Renders the visual identity of one project — its favicon, or its initials as the fallback.
82
+ *
83
+ * The favicon is served from the project folder, which requires a signed-in visitor, so the
84
+ * initials are shown whenever the favicon is missing or cannot be loaded.
85
+ *
86
+ * @private component of Agent Projects dashboards
87
+ */
88
+ export function AgentProjectIcon({
89
+ agentPermanentId,
90
+ project,
91
+ serverDomain = null,
92
+ currentServerDomain = null,
93
+ size,
94
+ className = '',
95
+ }: AgentProjectIconProps) {
96
+ const [isFaviconBroken, setIsFaviconBroken] = useState(false);
97
+ const faviconImageRef = useRef<HTMLImageElement | null>(null);
98
+ const iconClassNames = AGENT_PROJECT_ICON_CLASS_NAMES_BY_SIZE[size];
99
+ const faviconHref = !project.faviconRelativePath
100
+ ? null
101
+ : buildAgentProjectFileHrefForServer({
102
+ agentPermanentId,
103
+ projectName: project.projectName,
104
+ fileRelativePath: project.faviconRelativePath,
105
+ serverDomain,
106
+ currentServerDomain,
107
+ });
108
+
109
+ useEffect(() => {
110
+ // Note: A favicon rendered on the server can already fail before this component is hydrated,
111
+ // which loses its `error` event — an image which finished loading with no pixels is broken.
112
+ const faviconImage = faviconImageRef.current;
113
+ setIsFaviconBroken(faviconImage?.complete === true && faviconImage.naturalWidth === 0);
114
+ }, [faviconHref]);
115
+
116
+ return (
117
+ <span
118
+ className={`flex shrink-0 items-center justify-center overflow-hidden border border-blue-100 bg-blue-50 text-blue-700 ${iconClassNames.container} ${className}`}
119
+ aria-hidden
120
+ >
121
+ {faviconHref !== null && !isFaviconBroken ? (
122
+ // eslint-disable-next-line @next/next/no-img-element
123
+ <img
124
+ ref={faviconImageRef}
125
+ src={faviconHref}
126
+ alt=""
127
+ className={`h-full w-full object-contain ${iconClassNames.favicon}`}
128
+ onError={() => setIsFaviconBroken(true)}
129
+ />
130
+ ) : (
131
+ <span className={`font-bold leading-none ${iconClassNames.initials}`}>
132
+ {createAgentProjectInitials(project.projectName)}
133
+ </span>
134
+ )}
135
+ </span>
136
+ );
137
+ }
@@ -1,9 +1,9 @@
1
- import { FolderKanbanIcon } from 'lucide-react';
2
1
  import Link from 'next/link';
3
2
  import type { ReactNode } from 'react';
4
3
  import type { AgentProjectReferenceInfo } from '../../utils/agentProjects/AgentProjectReferenceInfo';
5
4
  import { buildAgentProjectProfileHrefForServer } from '../../utils/agentProjects/agentProjectHrefs';
6
5
  import { formatResourceBytes } from '../../utils/resourceMonitor/formatResourceMonitorValue';
6
+ import { AgentProjectIcon } from './AgentProjectIcon';
7
7
 
8
8
  /**
9
9
  * Visual variants supported by project references.
@@ -76,12 +76,22 @@ export function AgentProjectItem({
76
76
  serverDomain,
77
77
  currentServerDomain,
78
78
  });
79
+ const icon = (
80
+ <AgentProjectIcon
81
+ agentPermanentId={agentPermanentId}
82
+ project={project}
83
+ serverDomain={serverDomain}
84
+ currentServerDomain={currentServerDomain}
85
+ size={variant === 'small' ? 'small' : 'card'}
86
+ className={variant === 'small' ? 'mt-0.5' : ''}
87
+ />
88
+ );
79
89
 
80
90
  if (variant === 'small') {
81
- return <SmallAgentProjectItem href={href} project={project} className={className} />;
91
+ return <SmallAgentProjectItem href={href} project={project} icon={icon} className={className} />;
82
92
  }
83
93
 
84
- return <FullAgentProjectItem href={href} project={project} className={className} footer={footer} />;
94
+ return <FullAgentProjectItem href={href} project={project} icon={icon} className={className} footer={footer} />;
85
95
  }
86
96
 
87
97
  /**
@@ -98,6 +108,11 @@ type AgentProjectItemVariantProps = {
98
108
  */
99
109
  readonly project: AgentProjectItemInfo;
100
110
 
111
+ /**
112
+ * Rendered project icon.
113
+ */
114
+ readonly icon: ReactNode;
115
+
101
116
  /**
102
117
  * Optional CSS class overrides.
103
118
  */
@@ -115,16 +130,17 @@ type AgentProjectItemVariantProps = {
115
130
  * @param props - Project item variant props.
116
131
  * @returns Full project link card.
117
132
  */
118
- function FullAgentProjectItem({ href, project, className, footer }: AgentProjectItemVariantProps) {
133
+ function FullAgentProjectItem({ href, project, icon, className, footer }: AgentProjectItemVariantProps) {
119
134
  const isFooterVisible = footer !== undefined && footer !== null;
120
135
  const projectContent = (
121
136
  <>
122
137
  <div className="flex items-start gap-3">
123
- <div className="flex h-11 w-11 shrink-0 items-center justify-center rounded-lg border border-blue-100 bg-blue-50 text-blue-700">
124
- <FolderKanbanIcon className="h-5 w-5" aria-hidden />
125
- </div>
138
+ {icon}
126
139
  <div className="min-w-0 flex-1">
127
- <h3 className="truncate text-base font-semibold text-gray-950 group-hover:text-blue-700">
140
+ <h3
141
+ className="line-clamp-2 text-base font-semibold text-gray-950 group-hover:text-blue-700"
142
+ title={project.displayName}
143
+ >
128
144
  {project.displayName}
129
145
  </h3>
130
146
  {project.displayName !== project.projectName && (
@@ -170,14 +186,14 @@ function FullAgentProjectItem({ href, project, className, footer }: AgentProject
170
186
  * @param props - Project item variant props.
171
187
  * @returns Compact project link item.
172
188
  */
173
- function SmallAgentProjectItem({ href, project, className }: AgentProjectItemVariantProps) {
189
+ function SmallAgentProjectItem({ href, project, icon, className }: AgentProjectItemVariantProps) {
174
190
  return (
175
191
  <Link
176
192
  href={href}
177
193
  title={project.description || project.displayName}
178
194
  className={`inline-flex max-w-full items-start gap-2 rounded-lg border border-gray-200 bg-white px-3 py-2 text-left shadow-sm transition hover:border-blue-300 hover:bg-blue-50/50 ${className}`}
179
195
  >
180
- <FolderKanbanIcon className="mt-0.5 h-4 w-4 shrink-0 text-blue-600" aria-hidden />
196
+ {icon}
181
197
  <span className="min-w-0 flex-1">
182
198
  <span className="block truncate text-sm font-semibold text-gray-900">{project.displayName}</span>
183
199
  {project.description && (
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { useState } from 'react';
4
4
  import type { CloudflareDnsBatchRecordStatus } from '../../utils/cloudflare/CloudflareDnsBatchApplication';
5
- import type { DnsRecordSelection } from '../../utils/dnsRecords/DnsRecordInstruction';
5
+ import type { DnsRecordGroup } from '../../utils/dnsRecords/DnsRecordInstruction';
6
6
  import type { DnsRecordBatchPlan } from '../../utils/dnsRecords/resolveDnsRecordBatchPlan';
7
7
  import { CloudflareDnsExcludedRecordsNote } from './CloudflareDnsExcludedRecordsNote';
8
8
  import { useCloudflareDnsRecordImport } from './useCloudflareDnsRecordImport';
@@ -35,7 +35,7 @@ const CLOUDFLARE_DNS_IMPORT_STATUS_CLASS_NAMES: Record<CloudflareDnsBatchRecordS
35
35
  export function CloudflareDnsApiTokenImportStep({
36
36
  batchPlan,
37
37
  domain,
38
- recordSelection,
38
+ recordGroups,
39
39
  }: {
40
40
  /**
41
41
  * Records which can be imported at once together with the excluded ones.
@@ -48,15 +48,14 @@ export function CloudflareDnsApiTokenImportStep({
48
48
  readonly domain: string;
49
49
 
50
50
  /**
51
- * Whether all listed records or one listed alternative must be configured.
51
+ * All record groups displayed by the DNS manual.
52
52
  */
53
- readonly recordSelection: DnsRecordSelection;
53
+ readonly recordGroups: ReadonlyArray<DnsRecordGroup>;
54
54
  }) {
55
55
  const [apiToken, setApiToken] = useState('');
56
56
  const { isImporting, application, errorMessage, importRecords } = useCloudflareDnsRecordImport({
57
57
  domain,
58
- recordSelection,
59
- records: batchPlan.applicableRecords,
58
+ recordGroups,
60
59
  });
61
60
  const recordCount = batchPlan.applicableRecords.length;
62
61
 
@@ -1,4 +1,5 @@
1
- import type { DnsRecordSelection } from '../../utils/dnsRecords/DnsRecordInstruction';
1
+ import type { DnsRecordGroup } from '../../utils/dnsRecords/DnsRecordInstruction';
2
+ import { hasAlternativeDnsRecordGroup } from '../../utils/dnsRecords/dnsRecordGroups';
2
3
 
3
4
  /**
4
5
  * Explains how to verify the configured records after they were written to Cloudflare.
@@ -6,18 +7,18 @@ import type { DnsRecordSelection } from '../../utils/dnsRecords/DnsRecordInstruc
6
7
  * @private used by the Cloudflare DNS setup wizard
7
8
  */
8
9
  export function CloudflareDnsCheckStep({
9
- recordSelection,
10
+ recordGroups,
10
11
  }: {
11
12
  /**
12
- * Whether all listed records or one listed alternative must be configured.
13
+ * All record groups displayed by the DNS manual.
13
14
  */
14
- readonly recordSelection: DnsRecordSelection;
15
+ readonly recordGroups: ReadonlyArray<DnsRecordGroup>;
15
16
  }) {
16
17
  return (
17
18
  <div className="space-y-2">
18
19
  <p className="font-medium">Check the result</p>
19
20
  <ol className="list-decimal space-y-1 pl-5 text-amber-900">
20
- {recordSelection === 'one' ? (
21
+ {hasAlternativeDnsRecordGroup(recordGroups) ? (
21
22
  <li>Remove conflicting A, AAAA, or CNAME records for the same hostname.</li>
22
23
  ) : null}
23
24
  <li>Wait for DNS propagation.</li>
@@ -1,5 +1,6 @@
1
1
  import { isProxyableCloudflareDnsRecordType } from '../../utils/cloudflare/CloudflareApi';
2
- import type { DnsRecordInstruction, DnsRecordSelection } from '../../utils/dnsRecords/DnsRecordInstruction';
2
+ import type { DnsRecordGroup } from '../../utils/dnsRecords/DnsRecordInstruction';
3
+ import { countDnsRecordGroupRecords, isEveryDnsRecordGroupAlternative } from '../../utils/dnsRecords/dnsRecordGroups';
3
4
 
4
5
  /**
5
6
  * Direct Cloudflare dashboard URL for the DNS records page.
@@ -15,8 +16,7 @@ const CLOUDFLARE_DNS_RECORDS_URL = 'https://dash.cloudflare.com/?to=/:account/:z
15
16
  */
16
17
  export function CloudflareDnsManualStep({
17
18
  domain,
18
- recordSelection,
19
- records,
19
+ recordGroups,
20
20
  }: {
21
21
  /**
22
22
  * Hostname whose DNS records are being configured.
@@ -24,20 +24,16 @@ export function CloudflareDnsManualStep({
24
24
  readonly domain: string;
25
25
 
26
26
  /**
27
- * Whether all listed records or one listed alternative must be configured.
27
+ * All record groups displayed by the DNS manual.
28
28
  */
29
- readonly recordSelection: DnsRecordSelection;
30
-
31
- /**
32
- * The canonical DNS records displayed by the parent instruction panel.
33
- */
34
- readonly records: ReadonlyArray<DnsRecordInstruction>;
29
+ readonly recordGroups: ReadonlyArray<DnsRecordGroup>;
35
30
  }) {
31
+ const records = recordGroups.flatMap((recordGroup) => recordGroup.records);
36
32
  const isProxyStatusRelevant = records.some((record) => isProxyableCloudflareDnsRecordType(record.type));
37
- const recordSelectionInstruction =
38
- recordSelection === 'all'
39
- ? `Repeat this for all ${records.length} record${records.length === 1 ? '' : 's'} shown above.`
40
- : 'Choose one of the record alternatives shown above.';
33
+ const recordCount = countDnsRecordGroupRecords(recordGroups);
34
+ const recordSelectionInstruction = isEveryDnsRecordGroupAlternative(recordGroups)
35
+ ? 'Choose one of the record alternatives shown above.'
36
+ : `Repeat this for all ${recordCount} record${recordCount === 1 ? '' : 's'} shown above.`;
41
37
 
42
38
  return (
43
39
  <div className="space-y-2">