@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
@@ -0,0 +1,167 @@
1
+ /**
2
+ * `rel` values of one `<link/>` tag recognized as the icon of a page, ordered by priority.
3
+ *
4
+ * The values are compared against the `rel` attribute normalized to lowercase single-spaced tokens.
5
+ */
6
+ const FAVICON_LINK_RELATIONS = [
7
+ 'icon',
8
+ 'shortcut icon',
9
+ 'icon shortcut',
10
+ 'apple-touch-icon',
11
+ 'apple-touch-icon-precomposed',
12
+ 'mask-icon',
13
+ ] as const;
14
+
15
+ /**
16
+ * Matches the content of the `<title/>` element of one HTML document.
17
+ */
18
+ const HTML_TITLE_ELEMENT_REGEX = /<title\b[^>]*>([\s\S]*?)<\/title\s*>/i;
19
+
20
+ /**
21
+ * Matches every `<link/>` tag of one HTML document.
22
+ */
23
+ const HTML_LINK_TAG_REGEX = /<link\b[^>]*>/gi;
24
+
25
+ /**
26
+ * Matches one named or numeric HTML entity.
27
+ */
28
+ const HTML_ENTITY_REGEX = /&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/gi;
29
+
30
+ /**
31
+ * Replacements of the named HTML entities which can appear in a title or in an icon path.
32
+ */
33
+ const HTML_ENTITY_REPLACEMENTS: Record<string, string> = {
34
+ amp: '&',
35
+ apos: "'",
36
+ gt: '>',
37
+ lt: '<',
38
+ nbsp: ' ',
39
+ quot: '"',
40
+ };
41
+
42
+ /**
43
+ * Highest code point which can be decoded from a numeric HTML entity.
44
+ */
45
+ const MAXIMUM_UNICODE_CODE_POINT = 0x10ffff;
46
+
47
+ /**
48
+ * Presentation of one project resolved from its `index.html`.
49
+ */
50
+ export type AgentProjectIndexHtmlProfile = {
51
+ /**
52
+ * Content of the `<title/>` element, or `null` when the document has no usable title.
53
+ */
54
+ readonly title: string | null;
55
+
56
+ /**
57
+ * Icon `href` exactly as written in the document, or `null` when no icon is linked.
58
+ */
59
+ readonly faviconHref: string | null;
60
+ };
61
+
62
+ /**
63
+ * Parses the presentation of one project out of its `index.html`.
64
+ *
65
+ * Only the title and the linked icon are read, so the document is scanned with plain regular
66
+ * expressions instead of pulling a full HTML parser into the Agents Server.
67
+ *
68
+ * @param indexHtmlContent - Content of the project `index.html`.
69
+ * @returns Title and icon href found in the document.
70
+ */
71
+ export function parseAgentProjectIndexHtml(indexHtmlContent: string): AgentProjectIndexHtmlProfile {
72
+ return {
73
+ title: parseIndexHtmlTitle(indexHtmlContent),
74
+ faviconHref: parseIndexHtmlFaviconHref(indexHtmlContent),
75
+ };
76
+ }
77
+
78
+ /**
79
+ * Parses the `<title/>` of one HTML document.
80
+ *
81
+ * @param indexHtmlContent - Content of the project `index.html`.
82
+ * @returns Single-line title, or `null` when the document has no non-empty title.
83
+ */
84
+ function parseIndexHtmlTitle(indexHtmlContent: string): string | null {
85
+ const titleMatch = HTML_TITLE_ELEMENT_REGEX.exec(indexHtmlContent);
86
+ if (!titleMatch || titleMatch[1] === undefined) {
87
+ return null;
88
+ }
89
+
90
+ const title = decodeHtmlEntities(titleMatch[1]).replace(/\s+/gu, ' ').trim();
91
+ return title || null;
92
+ }
93
+
94
+ /**
95
+ * Parses the icon `href` linked by one HTML document.
96
+ *
97
+ * @param indexHtmlContent - Content of the project `index.html`.
98
+ * @returns Icon href of the best matching `<link/>` tag, or `null` when no icon is linked.
99
+ */
100
+ function parseIndexHtmlFaviconHref(indexHtmlContent: string): string | null {
101
+ let bestFaviconHref: string | null = null;
102
+ let bestFaviconRelationIndex: number = FAVICON_LINK_RELATIONS.length;
103
+
104
+ for (const linkTag of indexHtmlContent.match(HTML_LINK_TAG_REGEX) || []) {
105
+ const linkRelation = parseHtmlTagAttribute(linkTag, 'rel');
106
+ const linkHref = parseHtmlTagAttribute(linkTag, 'href');
107
+ if (linkRelation === null || !linkHref) {
108
+ continue;
109
+ }
110
+
111
+ const relationIndex = FAVICON_LINK_RELATIONS.indexOf(
112
+ linkRelation.toLowerCase().replace(/\s+/gu, ' ').trim() as (typeof FAVICON_LINK_RELATIONS)[number],
113
+ );
114
+ if (relationIndex === -1 || relationIndex >= bestFaviconRelationIndex) {
115
+ continue;
116
+ }
117
+
118
+ bestFaviconHref = linkHref;
119
+ bestFaviconRelationIndex = relationIndex;
120
+ }
121
+
122
+ return bestFaviconHref;
123
+ }
124
+
125
+ /**
126
+ * Parses one attribute out of a single HTML tag.
127
+ *
128
+ * @param htmlTag - One complete HTML tag including its angle brackets.
129
+ * @param attributeName - Lowercase attribute name.
130
+ * @returns Decoded attribute value, or `null` when the tag does not have the attribute.
131
+ */
132
+ function parseHtmlTagAttribute(htmlTag: string, attributeName: string): string | null {
133
+ const attributeMatch = new RegExp(`\\b${attributeName}\\s*=\\s*("[^"]*"|'[^']*'|[^\\s"'>]+)`, 'i').exec(htmlTag);
134
+ if (!attributeMatch || attributeMatch[1] === undefined) {
135
+ return null;
136
+ }
137
+
138
+ const rawAttributeValue = attributeMatch[1];
139
+ const isQuotedAttributeValue =
140
+ (rawAttributeValue.startsWith('"') && rawAttributeValue.endsWith('"')) ||
141
+ (rawAttributeValue.startsWith("'") && rawAttributeValue.endsWith("'"));
142
+
143
+ return decodeHtmlEntities(isQuotedAttributeValue ? rawAttributeValue.slice(1, -1) : rawAttributeValue).trim();
144
+ }
145
+
146
+ /**
147
+ * Decodes the HTML entities which can appear in a title or in an icon path.
148
+ *
149
+ * @param htmlText - Raw text taken from an HTML document.
150
+ * @returns Plain text.
151
+ */
152
+ function decodeHtmlEntities(htmlText: string): string {
153
+ return htmlText.replace(HTML_ENTITY_REGEX, (entity, entityName: string) => {
154
+ if (entityName.startsWith('#')) {
155
+ const characterCode = entityName.startsWith('#x')
156
+ ? Number.parseInt(entityName.slice(2), 16)
157
+ : Number.parseInt(entityName.slice(1), 10);
158
+
159
+ const isDecodableCharacterCode =
160
+ Number.isInteger(characterCode) && characterCode >= 0 && characterCode <= MAXIMUM_UNICODE_CODE_POINT;
161
+
162
+ return isDecodableCharacterCode ? String.fromCodePoint(characterCode) : entity;
163
+ }
164
+
165
+ return HTML_ENTITY_REPLACEMENTS[entityName.toLowerCase()] ?? entity;
166
+ });
167
+ }
@@ -0,0 +1,24 @@
1
+ import { AGENT_PROJECT_INDEX_HTML_FILE_NAMES } from './agentProjectFileNames';
2
+ import { parseAgentProjectIndexHtml, type AgentProjectIndexHtmlProfile } from './parseAgentProjectIndexHtml';
3
+ import { readAgentProjectRootTextFile } from './readAgentProjectRootTextFile';
4
+
5
+ /**
6
+ * Reads the presentation of one project from the `index.html` in its root.
7
+ *
8
+ * Only the root `index.html` is read, because it is the document the project serves on its own
9
+ * public URL — a nested one belongs to a build output or to a subpage of the project.
10
+ *
11
+ * @param projectPath - Absolute path of the project directory.
12
+ * @returns Title and icon href of the project, or `null` when the project has no `index.html`.
13
+ */
14
+ export async function readAgentProjectIndexHtmlProfile(
15
+ projectPath: string,
16
+ ): Promise<AgentProjectIndexHtmlProfile | null> {
17
+ const indexHtml = await readAgentProjectRootTextFile(projectPath, AGENT_PROJECT_INDEX_HTML_FILE_NAMES);
18
+
19
+ if (indexHtml === null) {
20
+ return null;
21
+ }
22
+
23
+ return parseAgentProjectIndexHtml(indexHtml.content);
24
+ }
@@ -1,6 +1,4 @@
1
- import { readdir, readFile } from 'fs/promises';
2
- import { join } from 'path';
3
- import { isMissingPathError } from './isMissingPathError';
1
+ import { readAgentProjectRootTextFile, type AgentProjectRootTextFile } from './readAgentProjectRootTextFile';
4
2
 
5
3
  /**
6
4
  * README filenames recognized inside project roots, ordered by display priority.
@@ -10,17 +8,7 @@ const AGENT_PROJECT_README_FILE_NAMES = ['readme.md', 'readme.markdown', 'readme
10
8
  /**
11
9
  * README file loaded from one agent project.
12
10
  */
13
- export type AgentProjectReadme = {
14
- /**
15
- * Original filename used on disk.
16
- */
17
- readonly fileName: string;
18
-
19
- /**
20
- * README content decoded as UTF-8 text.
21
- */
22
- readonly content: string;
23
- };
11
+ export type AgentProjectReadme = AgentProjectRootTextFile;
24
12
 
25
13
  /**
26
14
  * Reads the first recognized README file from a project directory.
@@ -29,43 +17,5 @@ export type AgentProjectReadme = {
29
17
  * @returns README content, or `null` when the project has no recognized README file.
30
18
  */
31
19
  export async function readAgentProjectReadme(projectPath: string): Promise<AgentProjectReadme | null> {
32
- let projectRootEntries;
33
-
34
- try {
35
- projectRootEntries = await readdir(projectPath, { withFileTypes: true });
36
- } catch (error) {
37
- if (isMissingPathError(error)) {
38
- return null;
39
- }
40
-
41
- throw error;
42
- }
43
-
44
- const projectFileNameByNormalizedName = new Map(
45
- projectRootEntries
46
- .filter((projectRootEntry) => projectRootEntry.isFile())
47
- .map((projectRootEntry) => [projectRootEntry.name.toLowerCase(), projectRootEntry.name]),
48
- );
49
-
50
- for (const readmeFileName of AGENT_PROJECT_README_FILE_NAMES) {
51
- const projectReadmeFileName = projectFileNameByNormalizedName.get(readmeFileName);
52
- if (!projectReadmeFileName) {
53
- continue;
54
- }
55
-
56
- try {
57
- return {
58
- fileName: projectReadmeFileName,
59
- content: await readFile(join(projectPath, projectReadmeFileName), 'utf-8'),
60
- };
61
- } catch (error) {
62
- if (isMissingPathError(error)) {
63
- return null;
64
- }
65
-
66
- throw error;
67
- }
68
- }
69
-
70
- return null;
20
+ return readAgentProjectRootTextFile(projectPath, AGENT_PROJECT_README_FILE_NAMES);
71
21
  }
@@ -0,0 +1,73 @@
1
+ import { readdir, readFile } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { isMissingPathError } from './isMissingPathError';
4
+
5
+ /**
6
+ * Text file loaded from the root of one agent project.
7
+ */
8
+ export type AgentProjectRootTextFile = {
9
+ /**
10
+ * Original filename used on disk.
11
+ */
12
+ readonly fileName: string;
13
+
14
+ /**
15
+ * File content decoded as UTF-8 text.
16
+ */
17
+ readonly content: string;
18
+ };
19
+
20
+ /**
21
+ * Reads the first recognized text file from the root of one project directory.
22
+ *
23
+ * Project files are written by the agent, so their filename casing cannot be relied on — the
24
+ * recognized filenames are matched case-insensitively and the real filename on disk is preserved.
25
+ *
26
+ * @param projectPath - Absolute path of the project directory.
27
+ * @param recognizedFileNames - Lowercase filenames ordered by priority.
28
+ * @returns Content of the first matching file, or `null` when the project has none of them.
29
+ */
30
+ export async function readAgentProjectRootTextFile(
31
+ projectPath: string,
32
+ recognizedFileNames: ReadonlyArray<string>,
33
+ ): Promise<AgentProjectRootTextFile | null> {
34
+ let projectRootEntries;
35
+
36
+ try {
37
+ projectRootEntries = await readdir(projectPath, { withFileTypes: true });
38
+ } catch (error) {
39
+ if (isMissingPathError(error)) {
40
+ return null;
41
+ }
42
+
43
+ throw error;
44
+ }
45
+
46
+ const projectFileNameByNormalizedName = new Map(
47
+ projectRootEntries
48
+ .filter((projectRootEntry) => projectRootEntry.isFile())
49
+ .map((projectRootEntry) => [projectRootEntry.name.toLowerCase(), projectRootEntry.name]),
50
+ );
51
+
52
+ for (const recognizedFileName of recognizedFileNames) {
53
+ const projectFileName = projectFileNameByNormalizedName.get(recognizedFileName.toLowerCase());
54
+ if (!projectFileName) {
55
+ continue;
56
+ }
57
+
58
+ try {
59
+ return {
60
+ fileName: projectFileName,
61
+ content: await readFile(join(projectPath, projectFileName), 'utf-8'),
62
+ };
63
+ } catch (error) {
64
+ if (isMissingPathError(error)) {
65
+ return null;
66
+ }
67
+
68
+ throw error;
69
+ }
70
+ }
71
+
72
+ return null;
73
+ }
@@ -0,0 +1,108 @@
1
+ import { stat } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { AGENT_PROJECT_CONVENTIONAL_FAVICON_RELATIVE_PATHS } from './agentProjectFileNames';
4
+ import { isSafeAgentProjectPathSegment } from './agentProjectsPaths';
5
+ import { isMissingPathError } from './isMissingPathError';
6
+ import { resolveAgentProjectFileContentType } from './resolveAgentProjectFileContentType';
7
+
8
+ /**
9
+ * Matches an icon reference which is not served from the project folder itself,
10
+ * for example `https://example.com/favicon.ico`, `//example.com/favicon.ico` or a `data:` URI.
11
+ */
12
+ const EXTERNAL_ICON_HREF_REGEX = /^([a-z][a-z0-9+.-]*:|\/\/)/i;
13
+
14
+ /**
15
+ * Content type prefix every usable project icon file must have.
16
+ */
17
+ const ICON_CONTENT_TYPE_PREFIX = 'image/';
18
+
19
+ /**
20
+ * Resolves the icon of one project as a path relative to the project root.
21
+ *
22
+ * The icon linked by the project `index.html` wins, the conventional favicon locations are searched
23
+ * afterwards. Only files which really exist inside the project folder are returned, so the resolved
24
+ * path can always be served through the project file route.
25
+ *
26
+ * @param options - Project directory and the icon href linked by its `index.html`.
27
+ * @returns Project-relative icon path using `/` separators, or `null` when the project has no icon.
28
+ */
29
+ export async function resolveAgentProjectFaviconRelativePath(options: {
30
+ readonly projectPath: string;
31
+ readonly indexHtmlFaviconHref: string | null;
32
+ }): Promise<string | null> {
33
+ const linkedFaviconRelativePath = resolveLocalIconRelativePath(options.indexHtmlFaviconHref);
34
+ const faviconRelativePathCandidates = [
35
+ ...(linkedFaviconRelativePath === null ? [] : [linkedFaviconRelativePath]),
36
+ ...AGENT_PROJECT_CONVENTIONAL_FAVICON_RELATIVE_PATHS,
37
+ ];
38
+
39
+ for (const faviconRelativePathCandidate of faviconRelativePathCandidates) {
40
+ if (await isExistingProjectIconFile(options.projectPath, faviconRelativePathCandidate)) {
41
+ return faviconRelativePathCandidate;
42
+ }
43
+ }
44
+
45
+ return null;
46
+ }
47
+
48
+ /**
49
+ * Normalizes one icon href written in a project `index.html` into a project-relative path.
50
+ *
51
+ * The href is written by the agent and therefore untrusted — an icon hosted outside of the project
52
+ * folder and any path escaping the project root are refused instead of being reported as an error.
53
+ *
54
+ * @param iconHref - Icon href exactly as written in the document.
55
+ * @returns Project-relative icon path using `/` separators, or `null` when the href is not usable.
56
+ */
57
+ function resolveLocalIconRelativePath(iconHref: string | null): string | null {
58
+ const trimmedIconHref = (iconHref || '').trim();
59
+
60
+ if (!trimmedIconHref || EXTERNAL_ICON_HREF_REGEX.test(trimmedIconHref)) {
61
+ return null;
62
+ }
63
+
64
+ const iconPath = trimmedIconHref.split(/[?#]/u)[0] || '';
65
+ let iconPathSegments: ReadonlyArray<string>;
66
+
67
+ try {
68
+ iconPathSegments = iconPath
69
+ .split('/')
70
+ .filter((iconPathSegment) => iconPathSegment !== '' && iconPathSegment !== '.')
71
+ .map((iconPathSegment) => decodeURIComponent(iconPathSegment));
72
+ } catch {
73
+ return null;
74
+ }
75
+
76
+ if (iconPathSegments.length === 0 || !iconPathSegments.every(isSafeAgentProjectPathSegment)) {
77
+ return null;
78
+ }
79
+
80
+ return iconPathSegments.join('/');
81
+ }
82
+
83
+ /**
84
+ * Returns whether one project-relative path points to an image file inside the project.
85
+ *
86
+ * @param projectPath - Absolute path of the project directory.
87
+ * @param iconRelativePath - Project-relative icon path using `/` separators.
88
+ * @returns `true` when the path is an existing image file.
89
+ */
90
+ async function isExistingProjectIconFile(projectPath: string, iconRelativePath: string): Promise<boolean> {
91
+ const iconPathSegments = iconRelativePath.split('/');
92
+ const iconFileName = iconPathSegments[iconPathSegments.length - 1] || '';
93
+
94
+ if (!resolveAgentProjectFileContentType(iconFileName).startsWith(ICON_CONTENT_TYPE_PREFIX)) {
95
+ return false;
96
+ }
97
+
98
+ try {
99
+ const iconStats = await stat(join(projectPath, ...iconPathSegments));
100
+ return iconStats.isFile();
101
+ } catch (error) {
102
+ if (isMissingPathError(error)) {
103
+ return false;
104
+ }
105
+
106
+ throw error;
107
+ }
108
+ }
@@ -5,8 +5,10 @@ import type { AgentProjectInfo } from './AgentProjectInfo';
5
5
  import { resolveAgentProjectsRootPath, resolveSafeAgentProjectPath } from './agentProjectsPaths';
6
6
  import { isMissingPathError } from './isMissingPathError';
7
7
  import { measureDirectoryUsage } from './measureDirectoryUsage';
8
+ import { readAgentProjectIndexHtmlProfile } from './readAgentProjectIndexHtmlProfile';
8
9
  import { readAgentProjectReadme } from './readAgentProjectReadme';
9
- import { resolveAgentProjectReadmeProfile } from './resolveAgentProjectReadmeProfile';
10
+ import { resolveAgentProjectFaviconRelativePath } from './resolveAgentProjectFaviconRelativePath';
11
+ import { resolveAgentProjectProfile } from './resolveAgentProjectProfile';
10
12
 
11
13
  /**
12
14
  * Builds metadata for one project directory.
@@ -20,14 +22,20 @@ export async function createAgentProjectInfo(
20
22
  projectDirectoryName: string,
21
23
  ): Promise<AgentProjectInfo> {
22
24
  const projectPath = join(projectsRootPath, projectDirectoryName);
23
- const [projectUsage, isGitRepository, readme] = await Promise.all([
25
+ const [projectUsage, isGitRepository, readme, indexHtmlProfile] = await Promise.all([
24
26
  measureDirectoryUsage(projectPath),
25
27
  isGitRepositoryDirectory(projectPath),
26
28
  readAgentProjectReadme(projectPath),
29
+ readAgentProjectIndexHtmlProfile(projectPath),
27
30
  ]);
28
- const profile = resolveAgentProjectReadmeProfile({
31
+ const profile = resolveAgentProjectProfile({
29
32
  projectDirectoryName,
30
33
  readme,
34
+ indexHtmlTitle: indexHtmlProfile?.title ?? null,
35
+ });
36
+ const faviconRelativePath = await resolveAgentProjectFaviconRelativePath({
37
+ projectPath,
38
+ indexHtmlFaviconHref: indexHtmlProfile?.faviconHref ?? null,
31
39
  });
32
40
 
33
41
  return {
@@ -35,6 +43,7 @@ export async function createAgentProjectInfo(
35
43
  displayName: profile.displayName,
36
44
  description: profile.description,
37
45
  readmeFileName: profile.readmeFileName,
46
+ faviconRelativePath,
38
47
  relativePath: `${AGENT_PROJECTS_DIRECTORY_PATH}/${projectDirectoryName}`,
39
48
  absolutePath: projectPath,
40
49
  sizeBytes: projectUsage.sizeBytes,
@@ -1,6 +1,7 @@
1
1
  import { parseMarkdownSection, splitMarkdownIntoSections } from '@promptbook-local/markdown-utils';
2
2
  import type { string_markdown } from '@promptbook-local/types';
3
3
  import { stripMarkdownText } from '../stripMarkdownText';
4
+ import { humanizeAgentProjectName } from './humanizeAgentProjectName';
4
5
  import type { AgentProjectReadme } from './readAgentProjectReadme';
5
6
 
6
7
  /**
@@ -29,9 +30,9 @@ type AgentProjectReadmeSections = {
29
30
  };
30
31
 
31
32
  /**
32
- * Project profile values resolved from a project folder and optional README.
33
+ * Project profile values resolved from a project folder, its README and its `index.html`.
33
34
  */
34
- export type AgentProjectReadmeProfile = {
35
+ export type AgentProjectProfile = {
35
36
  /**
36
37
  * User-facing project name.
37
38
  */
@@ -49,35 +50,30 @@ export type AgentProjectReadmeProfile = {
49
50
  };
50
51
 
51
52
  /**
52
- * Resolves display metadata for one agent project from its README.
53
+ * Resolves display metadata for one agent project.
53
54
  *
54
- * @param options - Project folder name and optional README content.
55
+ * @param options - Project folder name, optional README content and optional `index.html` title.
55
56
  * @returns Project display profile.
56
57
  */
57
- export function resolveAgentProjectReadmeProfile(options: {
58
+ export function resolveAgentProjectProfile(options: {
58
59
  readonly projectDirectoryName: string;
59
60
  readonly readme: AgentProjectReadme | null;
60
- }): AgentProjectReadmeProfile {
61
- const { projectDirectoryName, readme } = options;
62
- if (!readme) {
63
- return {
64
- displayName: projectDirectoryName,
65
- description: '',
66
- readmeFileName: null,
67
- };
68
- }
69
-
70
- const sections = parseMarkdownProfileSections(readme.content);
71
- const displayName = resolveProjectDisplayName(
72
- projectDirectoryName,
73
- sections.firstExplicitHeadingSection?.title ?? null,
74
- );
75
- const description = resolveProjectDescription(readme.content, sections.firstSection?.content ?? readme.content);
61
+ readonly indexHtmlTitle: string | null;
62
+ }): AgentProjectProfile {
63
+ const { projectDirectoryName, readme, indexHtmlTitle } = options;
64
+ const sections = readme === null ? null : parseMarkdownProfileSections(readme.content);
76
65
 
77
66
  return {
78
- displayName,
79
- description,
80
- readmeFileName: readme.fileName,
67
+ displayName: resolveProjectDisplayName({
68
+ projectDirectoryName,
69
+ readmeHeadingTitle: sections?.firstExplicitHeadingSection?.title ?? null,
70
+ indexHtmlTitle,
71
+ }),
72
+ description:
73
+ readme === null
74
+ ? ''
75
+ : resolveProjectDescription(readme.content, sections?.firstSection?.content ?? readme.content),
76
+ readmeFileName: readme?.fileName ?? null,
81
77
  };
82
78
  }
83
79
 
@@ -112,19 +108,23 @@ function parseMarkdownProfileSections(markdown: string): AgentProjectReadmeSecti
112
108
  }
113
109
 
114
110
  /**
115
- * Resolves a project display name from the README heading or folder fallback.
111
+ * Resolves a project display name from the README heading, the `index.html` title or the folder name.
112
+ *
113
+ * A project which describes itself neither in a README nor in an `index.html` still gets a readable
114
+ * name, because its folder name is humanized — `prague-murders-map` reads as `Prague Murders Map`.
116
115
  *
117
- * @param projectDirectoryName - Project folder name.
118
- * @param parsedHeadingTitle - Title returned by the markdown section parser.
116
+ * @param options - Project folder name and the titles found in the project files.
119
117
  * @returns Display name.
120
118
  */
121
- function resolveProjectDisplayName(projectDirectoryName: string, parsedHeadingTitle: string | null): string {
122
- if (!parsedHeadingTitle) {
123
- return projectDirectoryName;
124
- }
119
+ function resolveProjectDisplayName(options: {
120
+ readonly projectDirectoryName: string;
121
+ readonly readmeHeadingTitle: string | null;
122
+ readonly indexHtmlTitle: string | null;
123
+ }): string {
124
+ const readmeDisplayName = options.readmeHeadingTitle === null ? '' : stripMarkdownText(options.readmeHeadingTitle);
125
+ const indexHtmlDisplayName = (options.indexHtmlTitle || '').trim();
125
126
 
126
- const displayName = stripMarkdownText(parsedHeadingTitle);
127
- return displayName || projectDirectoryName;
127
+ return readmeDisplayName || indexHtmlDisplayName || humanizeAgentProjectName(options.projectDirectoryName);
128
128
  }
129
129
 
130
130
  /**
@@ -0,0 +1,34 @@
1
+ import { listAgentProjectDomainRecords, resolveAgentProjectRuntimeBaseDomain } from './agentProjectRuntimeDomains';
2
+ import { resolveCurrentAgentProjectServerDomain } from './resolveCurrentAgentProjectServerDomain';
3
+
4
+ /**
5
+ * Resolves the stable public URLs of the projects of one agent.
6
+ *
7
+ * The public URL of one project comes from its persisted domain assignment, so it stays the same
8
+ * whether the project runtime is running or stopped.
9
+ *
10
+ * @param agentPermanentId - Permanent id of the agent owning the projects.
11
+ * @returns Public project URLs keyed by lowercase project name.
12
+ */
13
+ export async function resolveAgentProjectPublicUrls(agentPermanentId: string): Promise<ReadonlyMap<string, string>> {
14
+ const [projectDomainRecords, currentServerDomain] = await Promise.all([
15
+ listAgentProjectDomainRecords(),
16
+ resolveCurrentAgentProjectServerDomain(),
17
+ ]);
18
+ const serverDomain = resolveAgentProjectRuntimeBaseDomain(currentServerDomain);
19
+ const publicUrlByProjectName = new Map<string, string>();
20
+
21
+ for (const projectDomainRecord of projectDomainRecords) {
22
+ if (projectDomainRecord.agentPermanentId.toLowerCase() !== agentPermanentId.toLowerCase()) {
23
+ continue;
24
+ }
25
+
26
+ if (serverDomain && resolveAgentProjectRuntimeBaseDomain(projectDomainRecord.serverDomain) !== serverDomain) {
27
+ continue;
28
+ }
29
+
30
+ publicUrlByProjectName.set(projectDomainRecord.projectName.toLowerCase(), projectDomainRecord.publicUrl);
31
+ }
32
+
33
+ return publicUrlByProjectName;
34
+ }
@@ -81,23 +81,25 @@ export function createBookLanguageDocumentationPdfHtml(
81
81
  const branding = getPromptbookExportBranding();
82
82
  const documentHtml = groupHtmlHeadingSections(highlightBookCodeBlocksInHtml(renderMarkdown(markdown)));
83
83
 
84
- return `<!doctype html>
85
- <html lang="${escapeHtml(language)}">
86
- <head>
87
- <meta charset="utf-8" />
88
- <meta name="viewport" content="width=device-width, initial-scale=1" />
89
- ${createPromptbookBrandingMetaTags(branding)}
90
- <title>${escapeHtml(branding.productName)} - Book Language Manual</title>
91
- <style>${createBookLanguageDocumentationPdfStyles()}</style>
92
- </head>
93
- <body>
94
- <main>
95
- ${createPromptbookBrandingHeader(branding, logoDataUrl)}
96
- ${documentHtml}
97
- ${createPromptbookBrandingFooter(branding)}
98
- </main>
99
- </body>
100
- </html>`;
84
+ return spaceTrim(
85
+ (block) => `<!doctype html>
86
+ <html lang="${block(escapeHtml(language))}">
87
+ <head>
88
+ <meta charset="utf-8" />
89
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
90
+ ${block(createPromptbookBrandingMetaTags(branding))}
91
+ <title>${block(escapeHtml(branding.productName))} - Book Language Manual</title>
92
+ <style>${block(createBookLanguageDocumentationPdfStyles())}</style>
93
+ </head>
94
+ <body>
95
+ <main>
96
+ ${block(createPromptbookBrandingHeader(branding, logoDataUrl))}
97
+ ${block(documentHtml)}
98
+ ${block(createPromptbookBrandingFooter(branding))}
99
+ </main>
100
+ </body>
101
+ </html>`,
102
+ );
101
103
  }
102
104
 
103
105
  /**