@promptbook/cli 0.112.0-126 → 0.112.0-128

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 (190) hide show
  1. package/README.md +5 -5
  2. package/apps/agents-server/README.md +3 -0
  3. package/apps/agents-server/playwright.config.ts +1 -0
  4. package/apps/agents-server/public/promptbook-logo-blue.png +0 -0
  5. package/apps/agents-server/public/promptbook-logo-white.png +0 -0
  6. package/apps/agents-server/src/app/[agentName]/layout.tsx +1 -0
  7. package/apps/agents-server/src/app/actions.ts +2 -2
  8. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +68 -36
  9. package/apps/agents-server/src/app/agents/[agentName]/ActiveAgentBreadcrumbBinder.tsx +30 -0
  10. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +2 -0
  11. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistoryPayloadState.ts +38 -4
  12. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatHistorySyncOperations.ts +4 -1
  13. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +19 -15
  14. package/apps/agents-server/src/app/agents/[agentName]/chat/useCanonicalAgentChatPanelState.ts +58 -7
  15. package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +47 -1
  16. package/apps/agents-server/src/app/api/chat/citation-label/route.ts +133 -0
  17. package/apps/agents-server/src/app/globals.css +78 -0
  18. package/apps/agents-server/src/components/Header/ActiveAgentBreadcrumbContext.tsx +82 -0
  19. package/apps/agents-server/src/components/Header/useHeaderActiveAgent.ts +26 -7
  20. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +35 -32
  21. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoNewAgentWizard.tsx +151 -0
  22. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/ManGoOnboardingNavigation.tsx +50 -0
  23. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +125 -0
  24. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/DropZone.tsx +83 -0
  25. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/EmailTestRun.tsx +216 -0
  26. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/KnowledgeList.tsx +79 -0
  27. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/Logo.tsx +20 -0
  28. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +154 -0
  29. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +188 -0
  30. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/RailStepper.tsx +115 -0
  31. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/StepFrame.tsx +47 -0
  32. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/TestChat.tsx +159 -0
  33. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +114 -0
  34. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/brand/RailArtwork.tsx +60 -0
  35. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +135 -0
  36. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/DoneStep.tsx +215 -0
  37. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/KnowledgeStep.tsx +152 -0
  38. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/TestStep.tsx +262 -0
  39. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +64 -0
  40. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Badge.tsx +41 -0
  41. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Banner.tsx +69 -0
  42. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Button.tsx +77 -0
  43. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Card.tsx +33 -0
  44. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Field.tsx +103 -0
  45. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/IconButton.tsx +40 -0
  46. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/Spinner.tsx +14 -0
  47. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ui/tokens.ts +37 -0
  48. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +62 -0
  49. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/emailScenarios.ts +22 -0
  50. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/steps.ts +46 -0
  51. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/index.ts +11 -0
  52. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/cn.ts +4 -0
  53. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/format.ts +9 -0
  54. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/id.ts +11 -0
  55. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentEvalService.ts +30 -0
  56. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/agentTestService.ts +69 -0
  57. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +21 -0
  58. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +107 -0
  59. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +45 -0
  60. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/uploadService.ts +27 -0
  61. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +121 -0
  62. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/types.ts +52 -0
  63. package/apps/agents-server/src/components/NewAgentDialog/createNewAgentWizardSource.ts +1 -1
  64. package/apps/agents-server/src/components/NewAgentDialog/trackNewAgentCreationEvent.ts +1 -1
  65. package/apps/agents-server/src/components/NewAgentDialog/useNewAgentDialog.tsx +76 -0
  66. package/apps/agents-server/src/constants/newAgentWizard.ts +17 -8
  67. package/apps/agents-server/src/database/getMetadata.ts +37 -1
  68. package/apps/agents-server/src/database/metadataDefaults.ts +18 -7
  69. package/apps/agents-server/src/database/migrations/2026-06-2200-new-agent-wizard-metadata-key.sql +27 -0
  70. package/apps/agents-server/src/database/migrations/2026-06-2201-new-agent-wizard-mango-default.sql +11 -0
  71. package/apps/agents-server/src/generated/reservedPaths.ts +2 -0
  72. package/apps/agents-server/src/languages/translations/english.yaml +1 -1
  73. package/apps/agents-server/src/tools/createChatAttachmentToolFunctions.ts +8 -4
  74. package/apps/agents-server/src/utils/chat/resolveAgentsServerCitationLabel.ts +130 -0
  75. package/apps/agents-server/src/utils/chat/resolveCitationSourceLabel.ts +436 -0
  76. package/apps/agents-server/src/utils/knowledge/resolveWebsiteKnowledgeSourcesForServer.ts +10 -1
  77. package/apps/agents-server/src/utils/session.ts +62 -5
  78. package/apps/agents-server/src/utils/transpilers/resolveTranspiledTeamExport.ts +10 -10
  79. package/apps/agents-server/src/utils/userChat/userChatProgressCard.ts +198 -63
  80. package/apps/agents-server/src/utils/vpsConfiguration.ts +1 -0
  81. package/apps/agents-server/src/utils/vpsSelfUpdate.ts +81 -8
  82. package/esm/index.es.js +1052 -455
  83. package/esm/index.es.js.map +1 -1
  84. package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
  85. package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
  86. package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
  87. package/esm/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
  88. package/esm/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  89. package/esm/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
  90. package/esm/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  91. package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
  92. package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
  93. package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
  94. package/esm/src/_packages/components.index.d.ts +2 -0
  95. package/esm/src/_packages/types.index.d.ts +2 -0
  96. package/esm/src/avatars/avatarAnimationScheduler.d.ts +4 -0
  97. package/esm/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
  98. package/esm/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
  99. package/esm/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
  100. package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  101. package/esm/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
  102. package/esm/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
  103. package/esm/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
  104. package/esm/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
  105. package/esm/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
  106. package/esm/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
  107. package/esm/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
  108. package/esm/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
  109. package/esm/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
  110. package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
  111. package/esm/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
  112. package/esm/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
  113. package/esm/src/version.d.ts +1 -1
  114. package/package.json +1 -1
  115. package/src/_packages/components.index.ts +2 -0
  116. package/src/_packages/types.index.ts +2 -0
  117. package/src/avatars/avatarAnimationScheduler.ts +61 -20
  118. package/src/avatars/visuals/octopus3d2AvatarVisual.ts +106 -21
  119. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +131 -28
  120. package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +18 -2
  121. package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +7 -1
  122. package/src/book-components/Chat/Chat/Chat.tsx +4 -0
  123. package/src/book-components/Chat/Chat/ChatCitationModal.tsx +17 -3
  124. package/src/book-components/Chat/Chat/ChatMessageItem.tsx +22 -2
  125. package/src/book-components/Chat/Chat/ChatMessageList.tsx +6 -0
  126. package/src/book-components/Chat/Chat/ChatProps.tsx +6 -0
  127. package/src/book-components/Chat/Chat/ChatToolCallModal.tsx +4 -0
  128. package/src/book-components/Chat/Chat/ChatToolCallModalContent.tsx +4 -0
  129. package/src/book-components/Chat/Chat/TeamToolCallModalContent.tsx +16 -3
  130. package/src/book-components/Chat/Chat/useChatPostprocessedMessages.ts +13 -2
  131. package/src/book-components/Chat/SourceChip/SourceChip.module.css +8 -0
  132. package/src/book-components/Chat/SourceChip/SourceChip.tsx +19 -5
  133. package/src/book-components/Chat/hooks/useResolvedCitationLabel.ts +65 -0
  134. package/src/book-components/Chat/save/html/htmlSaveFormatDefinition.ts +315 -88
  135. package/src/book-components/Chat/save/react/reactSaveFormatDefinition.ts +7 -1
  136. package/src/book-components/Chat/types/ChatMessage.ts +5 -0
  137. package/src/book-components/Chat/types/ChatParticipant.ts +1 -1
  138. package/src/book-components/Chat/types/CitationLabelResolver.ts +9 -0
  139. package/src/book-components/Chat/utils/citationHelpers.ts +90 -2
  140. package/src/book-components/Chat/utils/createCitationFootnoteRenderModel.ts +3 -0
  141. package/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.ts +178 -0
  142. package/src/book-components/Chat/utils/parseCitationsFromContent.ts +6 -0
  143. package/src/cli/cli-commands/agents-server/ensureAgentsServerEnvFile.ts +13 -2
  144. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  145. package/src/cli/cli-commands/coder/run.ts +17 -20
  146. package/src/cli/cli-commands/coder/server.ts +13 -16
  147. package/src/cli/common/$deprecateCliCommand.ts +10 -1
  148. package/src/commitments/GOAL/GOAL.ts +7 -2
  149. package/src/commitments/LANGUAGE/LANGUAGE.ts +7 -2
  150. package/src/commitments/TEAM/TEAM.ts +12 -1
  151. package/src/commitments/USE_PROJECT/createUseProjectToolFunctions.ts +8 -1
  152. package/src/import-plugins/JsonFileImportPlugin.ts +15 -2
  153. package/src/import-plugins/TextFileImportPlugin.ts +8 -1
  154. package/src/llm-providers/_common/register/$registeredLlmToolsMessage.ts +6 -1
  155. package/src/other/templates/getTemplatesPipelineCollection.ts +713 -785
  156. package/src/utils/chat/chatAttachments/resolveChatAttachmentContent.ts +8 -1
  157. package/src/version.ts +2 -2
  158. package/src/versions.txt +1 -0
  159. package/umd/index.umd.js +1055 -458
  160. package/umd/index.umd.js.map +1 -1
  161. package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
  162. package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +2 -2
  163. package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +50 -0
  164. package/umd/scripts/run-codex-prompts/server/buildCoderServerRunState.d.ts +23 -0
  165. package/umd/scripts/run-codex-prompts/server/coderServerHtml.d.ts +1 -1
  166. package/umd/scripts/run-codex-prompts/server/runCoderHttpServer.d.ts +13 -1
  167. package/umd/scripts/run-codex-prompts/server/updatePromptSection.d.ts +1 -1
  168. package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -0
  169. package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +4 -0
  170. package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +1 -0
  171. package/umd/src/_packages/components.index.d.ts +2 -0
  172. package/umd/src/_packages/types.index.d.ts +2 -0
  173. package/umd/src/avatars/avatarAnimationScheduler.d.ts +4 -0
  174. package/umd/src/book-components/Chat/Chat/ChatCitationModal.d.ts +2 -0
  175. package/umd/src/book-components/Chat/Chat/ChatMessageItem.d.ts +4 -0
  176. package/umd/src/book-components/Chat/Chat/ChatMessageList.d.ts +4 -0
  177. package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +5 -0
  178. package/umd/src/book-components/Chat/Chat/ChatToolCallModal.d.ts +2 -0
  179. package/umd/src/book-components/Chat/Chat/ChatToolCallModalContent.d.ts +3 -1
  180. package/umd/src/book-components/Chat/Chat/TeamToolCallModalContent.d.ts +2 -0
  181. package/umd/src/book-components/Chat/SourceChip/SourceChip.d.ts +6 -1
  182. package/umd/src/book-components/Chat/hooks/useResolvedCitationLabel.d.ts +12 -0
  183. package/umd/src/book-components/Chat/types/ChatMessage.d.ts +4 -0
  184. package/umd/src/book-components/Chat/types/ChatParticipant.d.ts +1 -1
  185. package/umd/src/book-components/Chat/types/CitationLabelResolver.d.ts +8 -0
  186. package/umd/src/book-components/Chat/utils/citationHelpers.d.ts +9 -0
  187. package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.d.ts +14 -0
  188. package/umd/src/book-components/Chat/utils/decodeJsonUnicodeEscapesInMarkdownText.test.d.ts +1 -0
  189. package/umd/src/book-components/Chat/utils/parseCitationsFromContent.d.ts +4 -0
  190. package/umd/src/version.d.ts +1 -1
@@ -0,0 +1,125 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+
5
+ import type { string_book } from '../../../../../../../src/book-2.0/agent-source/string_book';
6
+ import { BookEditor } from '../../../../../../../src/book-components/BookEditor/BookEditor';
7
+ import { convertToBook } from '../services/bookService';
8
+ import { Badge } from './ui/Badge';
9
+ import { Button } from './ui/Button';
10
+ import { Spinner } from './ui/Spinner';
11
+
12
+ type Phase = 'idle' | 'loading' | 'ready' | 'error';
13
+
14
+ /**
15
+ * Converts the editor's markdown draft into canonical Book language via the `generateBook`
16
+ * endpoint and shows the validated result. Optional, on-demand — keeps the free-markdown
17
+ * editing flow intact while exposing the "real" Book artifact.
18
+ */
19
+ export function BookLanguagePanel({ source }: { readonly source: string }) {
20
+ const [phase, setPhase] = useState<Phase>('idle');
21
+ const [book, setBook] = useState('');
22
+ const [isValid, setIsValid] = useState(true);
23
+ const [error, setError] = useState<string | null>(null);
24
+ const [generatedFrom, setGeneratedFrom] = useState('');
25
+ const [copied, setCopied] = useState(false);
26
+
27
+ async function generate() {
28
+ setPhase('loading');
29
+ setError(null);
30
+ try {
31
+ const result = await convertToBook(source);
32
+ setBook(result.book);
33
+ setIsValid(result.isValid);
34
+ setGeneratedFrom(source);
35
+ setPhase('ready');
36
+ } catch (caught) {
37
+ setError(caught instanceof Error ? caught.message : 'Převod na Book selhal.');
38
+ setPhase('error');
39
+ }
40
+ }
41
+
42
+ function copy() {
43
+ void navigator.clipboard?.writeText(book).then(() => {
44
+ setCopied(true);
45
+ setTimeout(() => setCopied(false), 1500);
46
+ });
47
+ }
48
+
49
+ const isStale = phase === 'ready' && source !== generatedFrom;
50
+
51
+ return (
52
+ <div className="mt-5 rounded-2xl border border-zinc-200/60 bg-white p-5 shadow-[var(--ob-shadow-sm)]">
53
+ <div className="flex items-center justify-between gap-3">
54
+ <div className="min-w-0">
55
+ <div className="text-sm font-semibold text-zinc-800">Book language</div>
56
+ <div className="mt-0.5 text-xs text-zinc-400">
57
+ Kanonická, validovaná podoba agenta vygenerovaná z vašeho draftu.
58
+ </div>
59
+ </div>
60
+ {phase === 'ready' && (
61
+ <Badge tone={isValid ? 'success' : 'warning'} dot>
62
+ {isValid ? 'Validní book' : 'Nevalidní'}
63
+ </Badge>
64
+ )}
65
+ </div>
66
+
67
+ {phase === 'idle' && (
68
+ <div className="mt-4">
69
+ <Button
70
+ variant="outline"
71
+ size="sm"
72
+ disabled={!source.trim()}
73
+ leadingIcon={<span aria-hidden>✨</span>}
74
+ onClick={() => void generate()}
75
+ >
76
+ Převést na Book language
77
+ </Button>
78
+ </div>
79
+ )}
80
+
81
+ {phase === 'loading' && (
82
+ <div className="mt-4 flex items-center gap-2 text-sm text-zinc-500">
83
+ <Spinner className="h-4 w-4" /> Generuji Book…
84
+ </div>
85
+ )}
86
+
87
+ {phase === 'error' && (
88
+ <div className="mt-4 rounded-xl border border-amber-200 bg-amber-50 px-3.5 py-2.5 text-sm text-amber-800">
89
+ <p>{error}</p>
90
+ <button
91
+ type="button"
92
+ onClick={() => void generate()}
93
+ className="mt-1 font-medium underline underline-offset-2"
94
+ >
95
+ Zkusit znovu
96
+ </button>
97
+ </div>
98
+ )}
99
+
100
+ {phase === 'ready' && (
101
+ <div className="mt-4">
102
+ <BookEditor value={book as string_book} isReadonly />
103
+ {isStale && (
104
+ <p className="mt-2 text-xs text-amber-600">
105
+ Draft se od převodu změnil — přegenerujte pro aktuální book.
106
+ </p>
107
+ )}
108
+ <div className="mt-3 flex items-center gap-2">
109
+ <Button
110
+ variant="outline"
111
+ size="sm"
112
+ leadingIcon={<span aria-hidden>↻</span>}
113
+ onClick={() => void generate()}
114
+ >
115
+ Přegenerovat
116
+ </Button>
117
+ <Button variant="ghost" size="sm" onClick={copy}>
118
+ {copied ? '✓ Zkopírováno' : 'Kopírovat'}
119
+ </Button>
120
+ </div>
121
+ </div>
122
+ )}
123
+ </div>
124
+ );
125
+ }
@@ -0,0 +1,83 @@
1
+ 'use client';
2
+
3
+ import { useRef, useState } from 'react';
4
+
5
+ import { cn } from '../lib/cn';
6
+
7
+ type DropZoneProps = {
8
+ readonly onFiles: (files: readonly File[]) => void;
9
+ readonly hint?: string;
10
+ readonly disabled?: boolean;
11
+ };
12
+
13
+ export function DropZone({ onFiles, hint, disabled }: DropZoneProps) {
14
+ const inputRef = useRef<HTMLInputElement>(null);
15
+ const [isDragging, setIsDragging] = useState(false);
16
+
17
+ function emit(fileList: FileList | null) {
18
+ const files = fileList ? Array.from(fileList) : [];
19
+ if (files.length > 0) {
20
+ onFiles(files);
21
+ }
22
+ }
23
+
24
+ return (
25
+ <div
26
+ role="button"
27
+ tabIndex={disabled ? -1 : 0}
28
+ aria-disabled={disabled}
29
+ onClick={() => !disabled && inputRef.current?.click()}
30
+ onKeyDown={(event) => {
31
+ if (!disabled && (event.key === 'Enter' || event.key === ' ')) {
32
+ event.preventDefault();
33
+ inputRef.current?.click();
34
+ }
35
+ }}
36
+ onDragEnter={(event) => {
37
+ event.preventDefault();
38
+ if (!disabled) setIsDragging(true);
39
+ }}
40
+ onDragOver={(event) => event.preventDefault()}
41
+ onDragLeave={() => setIsDragging(false)}
42
+ onDrop={(event) => {
43
+ event.preventDefault();
44
+ setIsDragging(false);
45
+ if (!disabled) emit(event.dataTransfer.files);
46
+ }}
47
+ className={cn(
48
+ 'group flex flex-col items-center justify-center rounded-2xl border-2 border-dashed px-6 py-12 text-center transition-all duration-200',
49
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)] focus-visible:ring-offset-2',
50
+ disabled && 'cursor-not-allowed opacity-60',
51
+ !disabled && isDragging
52
+ ? 'scale-[1.01] border-[color:var(--ob-accent-500)] bg-[color:var(--ob-accent-50)]'
53
+ : 'cursor-pointer border-zinc-300 bg-zinc-50/60 hover:border-[color:var(--ob-accent-300)] hover:bg-[color:var(--ob-accent-50)]/50',
54
+ )}
55
+ >
56
+ <input
57
+ ref={inputRef}
58
+ type="file"
59
+ multiple
60
+ className="hidden"
61
+ onChange={(event) => {
62
+ emit(event.target.files);
63
+ event.target.value = '';
64
+ }}
65
+ />
66
+ <span
67
+ className={cn(
68
+ 'flex h-12 w-12 items-center justify-center rounded-full text-2xl transition-colors',
69
+ isDragging
70
+ ? 'bg-[color:var(--ob-accent-100)]'
71
+ : 'bg-white shadow-[var(--ob-shadow-sm)] group-hover:bg-[color:var(--ob-accent-100)]',
72
+ )}
73
+ aria-hidden
74
+ >
75
+ 📂
76
+ </span>
77
+ <p className="mt-3 text-sm text-zinc-700">
78
+ <strong className="font-semibold text-zinc-900">Přetáhněte soubory sem</strong> nebo klikněte pro výběr
79
+ </p>
80
+ {hint && <p className="mt-1 text-xs text-zinc-400">{hint}</p>}
81
+ </div>
82
+ );
83
+ }
@@ -0,0 +1,216 @@
1
+ 'use client';
2
+
3
+ import { useState } from 'react';
4
+
5
+ import { createId } from '../lib/id';
6
+ import { cn } from '../lib/cn';
7
+ import { agentTestService } from '../services/agentTestService';
8
+ import { evaluateReply, type ReplyCheck } from '../services/agentEvalService';
9
+ import type { KnowledgeItem } from '../types';
10
+ import { Badge } from './ui/Badge';
11
+ import { Button } from './ui/Button';
12
+ import { CONTROL } from './ui/Field';
13
+ import { Spinner } from './ui/Spinner';
14
+
15
+ type Phase = 'idle' | 'running' | 'done' | 'error';
16
+
17
+ type EmailTestRunProps = {
18
+ readonly email: string;
19
+ readonly onEmailChange: (value: string) => void;
20
+ readonly bookSource: string;
21
+ readonly knowledge: readonly KnowledgeItem[];
22
+ readonly onEditBook: () => void;
23
+ };
24
+
25
+ function RunStep({
26
+ icon,
27
+ title,
28
+ children,
29
+ done,
30
+ }: {
31
+ readonly icon: string;
32
+ readonly title: string;
33
+ readonly children?: React.ReactNode;
34
+ readonly done?: boolean;
35
+ }) {
36
+ return (
37
+ <div className="flex gap-3 border-b border-zinc-100 py-3.5 last:border-b-0">
38
+ <div className="flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-lg bg-zinc-100 text-base" aria-hidden>
39
+ {icon}
40
+ </div>
41
+ <div className="min-w-0 flex-1">
42
+ <div className="flex items-center gap-2">
43
+ <span className="text-[13px] font-semibold text-zinc-800">{title}</span>
44
+ {done && (
45
+ <span className="text-[color:var(--ob-accent-600)]" aria-hidden>
46
+
47
+ </span>
48
+ )}
49
+ </div>
50
+ {children && <div className="mt-1 text-[13px] text-zinc-500">{children}</div>}
51
+ </div>
52
+ </div>
53
+ );
54
+ }
55
+
56
+ export function EmailTestRun({ email, onEmailChange, bookSource, knowledge, onEditBook }: EmailTestRunProps) {
57
+ const [phase, setPhase] = useState<Phase>('idle');
58
+ const [reply, setReply] = useState('');
59
+ const [error, setError] = useState<string | null>(null);
60
+ const [checks, setChecks] = useState<ReplyCheck[] | null>(null);
61
+ const [checksLoading, setChecksLoading] = useState(false);
62
+
63
+ const readyKnowledge = knowledge.filter((item) => item.status === 'ready').length;
64
+
65
+ async function run() {
66
+ const text = email.trim();
67
+ if (!text || phase === 'running') {
68
+ return;
69
+ }
70
+ setPhase('running');
71
+ setReply('');
72
+ setChecks(null);
73
+ setError(null);
74
+
75
+ try {
76
+ const result = await agentTestService.send({
77
+ bookSource,
78
+ knowledge,
79
+ messages: [{ id: createId(), role: 'user', content: text }],
80
+ });
81
+ setReply(result.content);
82
+ setPhase('done');
83
+
84
+ setChecksLoading(true);
85
+ try {
86
+ setChecks(await evaluateReply({ bookSource, customerEmail: text, reply: result.content }));
87
+ } catch {
88
+ setChecks([]);
89
+ } finally {
90
+ setChecksLoading(false);
91
+ }
92
+ } catch (caught) {
93
+ setError(caught instanceof Error ? caught.message : 'Testovací běh selhal.');
94
+ setPhase('error');
95
+ }
96
+ }
97
+
98
+ return (
99
+ <div className="space-y-4">
100
+ <div className="rounded-2xl border border-zinc-200/60 bg-white p-5 shadow-[var(--ob-shadow-sm)]">
101
+ <label htmlFor="email-test-input" className="mb-1.5 block text-[13px] font-semibold text-zinc-700">
102
+ Testovací vstup — e-mail od zákazníka
103
+ </label>
104
+ <textarea
105
+ id="email-test-input"
106
+ rows={4}
107
+ value={email}
108
+ onChange={(event) => onEmailChange(event.target.value)}
109
+ className={cn(CONTROL, 'resize-y')}
110
+ />
111
+ <div className="mt-3 flex items-center justify-between gap-3">
112
+ <span className="text-xs text-zinc-400">Vlastní text, nebo klikněte na scénář vlevo.</span>
113
+ <Button
114
+ isLoading={phase === 'running'}
115
+ leadingIcon={<span aria-hidden>▶</span>}
116
+ onClick={() => void run()}
117
+ disabled={email.trim().length === 0}
118
+ >
119
+ Spustit testovací běh
120
+ </Button>
121
+ </div>
122
+ </div>
123
+
124
+ {phase === 'error' && (
125
+ <div className="rounded-2xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800">
126
+ <div className="font-medium">Testovací běh se nezdařil.</div>
127
+ <p className="mt-1">{error}</p>
128
+ <button type="button" onClick={() => void run()} className="mt-1 font-medium underline underline-offset-2">
129
+ Zkusit znovu
130
+ </button>
131
+ </div>
132
+ )}
133
+
134
+ {(phase === 'running' || phase === 'done') && (
135
+ <div className="overflow-hidden rounded-2xl border border-zinc-200 bg-white shadow-[var(--ob-shadow-md)]">
136
+ <div className="flex items-center gap-2 border-b border-zinc-200 bg-zinc-50/80 px-4 py-2.5 text-[13px] font-medium text-zinc-600">
137
+ <span className="relative flex h-2 w-2" aria-hidden>
138
+ <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-75" />
139
+ <span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-500" />
140
+ </span>
141
+ Záznam testovacího běhu
142
+ <span className="ml-auto">
143
+ <Badge tone="success" dot>
144
+ Naživo
145
+ </Badge>
146
+ </span>
147
+ </div>
148
+
149
+ <div className="px-4">
150
+ <RunStep icon="📨" title="Vstup přijat: e-mail zákazníka" done>
151
+ E-mail předán agentovi ke zpracování.
152
+ </RunStep>
153
+ <RunStep icon="🧠" title="Prohledání znalostí" done>
154
+ {readyKnowledge > 0
155
+ ? `${readyKnowledge} ${readyKnowledge === 1 ? 'zdroj' : 'zdroje/ů'} připojeno k agentovi.`
156
+ : 'Bez znalostní báze — agent vychází jen z booku.'}
157
+ </RunStep>
158
+ <RunStep icon="✍️" title="Návrh odpovědi">
159
+ {phase === 'running' ? (
160
+ <span className="inline-flex items-center gap-2 text-zinc-500">
161
+ <Spinner className="h-4 w-4" /> Generuji odpověď…
162
+ </span>
163
+ ) : (
164
+ <>
165
+ <div className="mt-1 whitespace-pre-wrap rounded-xl border border-zinc-200 bg-zinc-50 p-3.5 text-[13px] leading-relaxed text-zinc-700">
166
+ {reply}
167
+ </div>
168
+ <p className="mt-2 text-[11px] text-zinc-400">
169
+ Toto je návrh — agent nic neodesílá, odpověď schvaluje operátor.
170
+ </p>
171
+ </>
172
+ )}
173
+ </RunStep>
174
+ </div>
175
+
176
+ {phase === 'done' && (
177
+ <div className="border-t border-zinc-200 bg-zinc-50/60 px-4 py-3.5">
178
+ <div className="mb-2 text-xs font-semibold text-zinc-500">Kontroly výsledku</div>
179
+ {checksLoading ? (
180
+ <div className="flex items-center gap-2 text-[13px] text-zinc-500">
181
+ <Spinner className="h-4 w-4" /> Hodnotím odpověď proti booku…
182
+ </div>
183
+ ) : checks && checks.length > 0 ? (
184
+ <ul className="space-y-1.5">
185
+ {checks.map((check, index) => (
186
+ <li
187
+ key={index}
188
+ className={cn(
189
+ 'flex items-start gap-2 text-[13px]',
190
+ check.status === 'ok' ? 'text-emerald-700' : 'text-amber-700',
191
+ )}
192
+ >
193
+ <span aria-hidden>{check.status === 'ok' ? '✓' : '⚠'}</span>
194
+ <span>{check.text}</span>
195
+ </li>
196
+ ))}
197
+ </ul>
198
+ ) : (
199
+ <div className="text-[13px] text-zinc-400">Bez připomínek.</div>
200
+ )}
201
+
202
+ <div className="mt-3 flex flex-wrap gap-2">
203
+ <Button variant="outline" size="sm" onClick={onEditBook}>
204
+ ✏️ Upravit book
205
+ </Button>
206
+ <Button variant="ghost" size="sm" leadingIcon={<span aria-hidden>↻</span>} onClick={() => void run()}>
207
+ Spustit znovu
208
+ </Button>
209
+ </div>
210
+ </div>
211
+ )}
212
+ </div>
213
+ )}
214
+ </div>
215
+ );
216
+ }
@@ -0,0 +1,79 @@
1
+ import type { KnowledgeItem, KnowledgeItemStatus } from '../types';
2
+ import { cn } from '../lib/cn';
3
+ import { formatFileSize } from '../lib/format';
4
+ import { Badge } from './ui/Badge';
5
+ import { IconButton } from './ui/IconButton';
6
+ import { Spinner } from './ui/Spinner';
7
+
8
+ function StatusChip({ status }: { readonly status: KnowledgeItemStatus }) {
9
+ if (status === 'uploading') {
10
+ return (
11
+ <span className="inline-flex items-center gap-1.5 text-xs text-zinc-500">
12
+ <Spinner className="h-3.5 w-3.5" /> Nahrávám…
13
+ </span>
14
+ );
15
+ }
16
+ if (status === 'error') {
17
+ return <Badge tone="error">Chyba</Badge>;
18
+ }
19
+ return (
20
+ <Badge tone="success" dot>
21
+ Připraveno
22
+ </Badge>
23
+ );
24
+ }
25
+
26
+ type KnowledgeListProps = {
27
+ readonly items: readonly KnowledgeItem[];
28
+ readonly onRemove: (id: string) => void;
29
+ };
30
+
31
+ export function KnowledgeList({ items, onRemove }: KnowledgeListProps) {
32
+ if (items.length === 0) {
33
+ return null;
34
+ }
35
+
36
+ return (
37
+ <ul className="space-y-2">
38
+ {items.map((item) => (
39
+ <li
40
+ key={item.id}
41
+ className={cn(
42
+ 'group flex items-center justify-between gap-3 rounded-xl border bg-white px-3.5 py-2.5 shadow-[var(--ob-shadow-xs)] transition-colors',
43
+ item.status === 'error'
44
+ ? 'border-red-200 bg-red-50/40'
45
+ : 'border-zinc-200 hover:border-zinc-300',
46
+ )}
47
+ >
48
+ <div className="flex min-w-0 items-center gap-2.5">
49
+ <span
50
+ className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-zinc-100 text-base"
51
+ aria-hidden
52
+ >
53
+ {item.kind === 'file' ? '📄' : '🔗'}
54
+ </span>
55
+ <div className="min-w-0">
56
+ <div className="truncate text-sm font-medium text-zinc-800">
57
+ {item.kind === 'file' ? item.name : item.url}
58
+ </div>
59
+ {item.kind === 'file' && (
60
+ <div className="text-xs text-zinc-400">{formatFileSize(item.size)}</div>
61
+ )}
62
+ </div>
63
+ </div>
64
+ <div className="flex flex-shrink-0 items-center gap-2">
65
+ <StatusChip status={item.status} />
66
+ <IconButton
67
+ size="sm"
68
+ label="Odebrat zdroj"
69
+ onClick={() => onRemove(item.id)}
70
+ className="opacity-60 hover:text-red-600 group-hover:opacity-100"
71
+ >
72
+ ×
73
+ </IconButton>
74
+ </div>
75
+ </li>
76
+ ))}
77
+ </ul>
78
+ );
79
+ }
@@ -0,0 +1,20 @@
1
+ import Image from 'next/image';
2
+
3
+ import { cn } from '../lib/cn';
4
+
5
+ /**
6
+ * Official Promptbook logo (symbol PNG from the brand kit) + wordmark in Outfit.
7
+ * Per the brand rules the mark itself is never recolored — we only switch between the
8
+ * provided variants: `white` for dark surfaces, `blue` for light ones.
9
+ */
10
+ export function Logo({ variant = 'white', className }: { readonly variant?: 'white' | 'blue'; readonly className?: string }) {
11
+ const src = variant === 'white' ? '/promptbook-logo-white.png' : '/promptbook-logo-blue.png';
12
+ return (
13
+ <span className={cn('inline-flex select-none items-center gap-2 text-lg tracking-tight', className)}>
14
+ <Image src={src} alt="Promptbook" width={28} height={28} className="h-7 w-7" />
15
+ <span className="ob-display font-medium">
16
+ Prompt<b className="font-semibold">book</b>
17
+ </span>
18
+ </span>
19
+ );
20
+ }