@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,262 @@
1
+ 'use client';
2
+
3
+ import { useRef, useState } from 'react';
4
+
5
+ import { EMAIL_SCENARIOS } from '../../config/emailScenarios';
6
+ import { ONBOARDING_STEPS } from '../../config/steps';
7
+ import { createId } from '../../lib/id';
8
+ import { cn } from '../../lib/cn';
9
+ import { agentTestService } from '../../services/agentTestService';
10
+ import { useManGoOnboardingNavigation } from '../../ManGoOnboardingNavigation';
11
+ import { useOnboarding } from '../../state/OnboardingProvider';
12
+ import type { ChatMessage } from '../../types';
13
+ import { EmailTestRun } from '../EmailTestRun';
14
+ import { SectionLabel, StepFooter, StepHeader } from '../StepFrame';
15
+ import { TestChat } from '../TestChat';
16
+ import { Badge } from '../ui/Badge';
17
+ import { Button } from '../ui/Button';
18
+ import { Card } from '../ui/Card';
19
+
20
+ type TestMode = 'email' | 'chat';
21
+
22
+ const SAMPLE_PROMPTS = [
23
+ 'Zákazník reklamuje zboží, které přišlo poškozené.',
24
+ 'Zákazník se ptá, proč mu nedorazilo zboží objednané před 3 dny.',
25
+ ];
26
+
27
+ export function TestStep() {
28
+ const { navigateToPath } = useManGoOnboardingNavigation();
29
+ const { state, update } = useOnboarding();
30
+
31
+ const [mode, setMode] = useState<TestMode>('email');
32
+ const [email, setEmail] = useState(EMAIL_SCENARIOS[1].email);
33
+
34
+ const [isSending, setIsSending] = useState(false);
35
+ const requestRef = useRef(0);
36
+
37
+ async function runAgent(history: readonly ChatMessage[]) {
38
+ const requestId = (requestRef.current += 1);
39
+ setIsSending(true);
40
+ try {
41
+ const reply = await agentTestService.send({
42
+ bookSource: state.bookSource,
43
+ knowledge: state.knowledge,
44
+ messages: history,
45
+ });
46
+ if (requestRef.current !== requestId) {
47
+ return;
48
+ }
49
+ update((prev) => ({
50
+ testMessages: [...prev.testMessages, { id: createId(), role: 'agent', content: reply.content }],
51
+ }));
52
+ } catch {
53
+ if (requestRef.current !== requestId) {
54
+ return;
55
+ }
56
+ update((prev) => ({
57
+ testMessages: [
58
+ ...prev.testMessages,
59
+ { id: createId(), role: 'agent', content: 'Omlouvám se, něco se pokazilo. Zkuste to prosím znovu.' },
60
+ ],
61
+ }));
62
+ } finally {
63
+ if (requestRef.current === requestId) {
64
+ setIsSending(false);
65
+ }
66
+ }
67
+ }
68
+
69
+ function send(text: string) {
70
+ const trimmed = text.trim();
71
+ if (!trimmed || isSending) {
72
+ return;
73
+ }
74
+ const history = [...state.testMessages, { id: createId(), role: 'user' as const, content: trimmed }];
75
+ update(() => ({ testMessages: history }));
76
+ void runAgent(history);
77
+ }
78
+
79
+ function retry() {
80
+ if (isSending) {
81
+ return;
82
+ }
83
+ const messages = state.testMessages;
84
+ let lastUser = -1;
85
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
86
+ if (messages[index].role === 'user') {
87
+ lastUser = index;
88
+ break;
89
+ }
90
+ }
91
+ if (lastUser < 0) {
92
+ return;
93
+ }
94
+ const history = messages.slice(0, lastUser + 1);
95
+ update(() => ({ testMessages: history }));
96
+ void runAgent(history);
97
+ }
98
+
99
+ function stop() {
100
+ requestRef.current += 1;
101
+ setIsSending(false);
102
+ }
103
+
104
+ const agentName = state.agentName.trim() || 'Nepojmenovaný agent';
105
+ const readyKnowledge = state.knowledge.filter((item) => item.status === 'ready').length;
106
+ const isRetryAvailable = !isSending && state.testMessages.some((message) => message.role === 'user');
107
+
108
+ return (
109
+ <div className="mx-auto max-w-4xl">
110
+ <StepHeader
111
+ eyebrow="Ověření agenta"
112
+ title="Otestujte agenta"
113
+ subtitle="Vyzkoušejte, jak agent reaguje na reálná zadání. Odpovídá naživo přes model — je to testovací režim, nic se zákazníkům neodesílá."
114
+ />
115
+
116
+ <div className="mb-6">
117
+ <ModeToggle mode={mode} onChange={setMode} />
118
+ </div>
119
+
120
+ <div className="grid items-start gap-6 md:grid-cols-[1fr_1.4fr]">
121
+ <div className="space-y-4">
122
+ <Card className="p-5">
123
+ <SectionLabel className="mb-3">Konfigurace agenta</SectionLabel>
124
+ <div className="text-sm font-bold text-zinc-900">{agentName}</div>
125
+ <div className="mt-4 space-y-2.5 border-t border-zinc-100 pt-4 text-sm">
126
+ <div className="flex items-center justify-between">
127
+ <span className="text-zinc-500">Book</span>
128
+ <button
129
+ type="button"
130
+ onClick={() => navigateToPath(ONBOARDING_STEPS[0].path)}
131
+ className="inline-flex items-center gap-1 rounded-full bg-[color:var(--ob-accent-50)] px-2.5 py-0.5 text-xs font-medium text-[color:var(--ob-accent-700)] transition-colors hover:bg-[color:var(--ob-accent-100)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)]"
132
+ >
133
+ <span aria-hidden>✏️</span> Upravit
134
+ </button>
135
+ </div>
136
+ <div className="flex items-center justify-between">
137
+ <span className="text-zinc-500">Znalosti</span>
138
+ <Badge tone={readyKnowledge > 0 ? 'success' : 'neutral'} dot={readyKnowledge > 0}>
139
+ {readyKnowledge} {readyKnowledge === 1 ? 'zdroj' : 'zdroje/ů'}
140
+ </Badge>
141
+ </div>
142
+ </div>
143
+ </Card>
144
+
145
+ {mode === 'email' ? (
146
+ <div>
147
+ <div className="mb-2 text-[13px] font-semibold text-zinc-600">Simulace vstupu:</div>
148
+ <div className="space-y-2">
149
+ {EMAIL_SCENARIOS.map((scenario) => (
150
+ <button
151
+ key={scenario.id}
152
+ type="button"
153
+ onClick={() => setEmail(scenario.email)}
154
+ className="flex w-full items-start gap-2.5 rounded-xl border border-zinc-200 bg-white px-3.5 py-2.5 text-left shadow-[var(--ob-shadow-xs)] transition-all hover:-translate-y-px hover:border-[color:var(--ob-accent-300)] hover:shadow-[var(--ob-shadow-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)]"
155
+ >
156
+ <span className="text-base" aria-hidden>
157
+ {scenario.icon}
158
+ </span>
159
+ <span>
160
+ <span className="block text-[13px] font-semibold text-zinc-800">
161
+ {scenario.label}
162
+ </span>
163
+ <span className="block text-[11px] text-zinc-400">
164
+ Vzorový e-mail — předvyplní vstup
165
+ </span>
166
+ </span>
167
+ </button>
168
+ ))}
169
+ </div>
170
+ </div>
171
+ ) : (
172
+ <div>
173
+ <div className="mb-2 text-[13px] font-semibold text-zinc-600">Zkuste zadat:</div>
174
+ <div className="space-y-2">
175
+ {SAMPLE_PROMPTS.map((prompt) => (
176
+ <button
177
+ key={prompt}
178
+ type="button"
179
+ disabled={isSending}
180
+ onClick={() => send(prompt)}
181
+ className="group flex w-full items-start gap-2 rounded-xl border border-zinc-200 bg-white px-3.5 py-2.5 text-left text-[13px] leading-relaxed text-zinc-600 shadow-[var(--ob-shadow-xs)] transition-all hover:-translate-y-px hover:border-[color:var(--ob-accent-300)] hover:text-zinc-900 hover:shadow-[var(--ob-shadow-sm)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)] disabled:cursor-not-allowed disabled:opacity-60"
182
+ >
183
+ <span
184
+ className="mt-0.5 text-[color:var(--ob-accent-400)] transition-colors group-hover:text-[color:var(--ob-accent-600)]"
185
+ aria-hidden
186
+ >
187
+
188
+ </span>
189
+ <span>„{prompt}“</span>
190
+ </button>
191
+ ))}
192
+ </div>
193
+ </div>
194
+ )}
195
+ </div>
196
+
197
+ {mode === 'email' ? (
198
+ <EmailTestRun
199
+ email={email}
200
+ onEmailChange={setEmail}
201
+ bookSource={state.bookSource}
202
+ knowledge={state.knowledge}
203
+ onEditBook={() => navigateToPath(ONBOARDING_STEPS[0].path)}
204
+ />
205
+ ) : (
206
+ <TestChat
207
+ messages={state.testMessages}
208
+ isSending={isSending}
209
+ onSend={send}
210
+ onStop={stop}
211
+ onRetry={isRetryAvailable ? retry : undefined}
212
+ />
213
+ )}
214
+ </div>
215
+
216
+ <StepFooter
217
+ left={
218
+ <Button variant="ghost" onClick={() => navigateToPath(ONBOARDING_STEPS[1].path)}>
219
+ ← Znalosti
220
+ </Button>
221
+ }
222
+ right={
223
+ <Button trailingIcon={<span aria-hidden>→</span>} onClick={() => navigateToPath(ONBOARDING_STEPS[3].path)}>
224
+ Uložit první verzi
225
+ </Button>
226
+ }
227
+ />
228
+ </div>
229
+ );
230
+ }
231
+
232
+ function ModeToggle({ mode, onChange }: { readonly mode: TestMode; readonly onChange: (mode: TestMode) => void }) {
233
+ const options: ReadonlyArray<{ id: TestMode; label: string; icon: string }> = [
234
+ { id: 'email', label: 'E-mailový test', icon: '📨' },
235
+ { id: 'chat', label: 'Konverzace', icon: '💬' },
236
+ ];
237
+ return (
238
+ <div className="inline-flex rounded-xl border border-zinc-200 bg-white p-0.5 shadow-[var(--ob-shadow-xs)]" role="tablist" aria-label="Režim testu">
239
+ {options.map((option) => {
240
+ const isActive = option.id === mode;
241
+ return (
242
+ <button
243
+ key={option.id}
244
+ type="button"
245
+ role="tab"
246
+ aria-selected={isActive}
247
+ onClick={() => onChange(option.id)}
248
+ className={cn(
249
+ 'inline-flex items-center gap-1.5 rounded-lg px-3.5 py-1.5 text-[13px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ob-ring)]',
250
+ isActive
251
+ ? 'bg-[color:var(--ob-accent-600)] text-white'
252
+ : 'text-zinc-500 hover:bg-zinc-100 hover:text-zinc-800',
253
+ )}
254
+ >
255
+ <span aria-hidden>{option.icon}</span>
256
+ {option.label}
257
+ </button>
258
+ );
259
+ })}
260
+ </div>
261
+ );
262
+ }
@@ -0,0 +1,64 @@
1
+ 'use client';
2
+
3
+ import { ONBOARDING_STEPS } from '../../config/steps';
4
+ import { useManGoOnboardingNavigation } from '../../ManGoOnboardingNavigation';
5
+ import { useOnboarding } from '../../state/OnboardingProvider';
6
+ import { SectionLabel, StepCard, StepFooter } from '../StepFrame';
7
+ import { Button } from '../ui/Button';
8
+ import { InputField, TextareaField } from '../ui/Field';
9
+
10
+ /**
11
+ * Entry screen of the wizard ("Řekněte mi o agentovi"). Captures the agent name + a
12
+ * one-sentence brief, then continues to the Book step where the draft is generated.
13
+ */
14
+ export function ZadaniStep() {
15
+ const { navigateToPath } = useManGoOnboardingNavigation();
16
+ const { state, update } = useOnboarding();
17
+ const isContinueEnabled = state.agentName.trim().length > 0 && state.agentBrief.trim().length > 0;
18
+
19
+ return (
20
+ <div className="mx-auto max-w-2xl">
21
+ <StepCard>
22
+ <SectionLabel className="text-[color:var(--ob-accent-600)]">Začněme</SectionLabel>
23
+ <h1 className="mt-2 text-balance text-3xl font-extrabold tracking-tight text-zinc-900">
24
+ Řekněte mi o agentovi
25
+ </h1>
26
+ <p className="mt-2.5 text-sm leading-relaxed text-zinc-500">
27
+ Stačí název a jedna věta o tom, co má agent dělat. Z toho připravíme draft booku, který si pak
28
+ libovolně upravíte.
29
+ </p>
30
+
31
+ <div className="mt-8 space-y-6">
32
+ <InputField
33
+ label="Název agenta"
34
+ placeholder="např. E-mail asistent pro Alzu"
35
+ value={state.agentName}
36
+ hint="Vyberte název srozumitelný pro klienta, ne pro technika."
37
+ onChange={(event) => update({ agentName: event.target.value })}
38
+ />
39
+ <TextareaField
40
+ label="Co má agent dělat?"
41
+ labelSuffix={<span className="font-normal text-zinc-400">(jedna věta stačí)</span>}
42
+ rows={2}
43
+ placeholder="např. Pomáhá zákaznickému servisu odpovídat na příchozí e-maily od zákazníků."
44
+ value={state.agentBrief}
45
+ onChange={(event) => update({ agentBrief: event.target.value })}
46
+ />
47
+ </div>
48
+
49
+ <StepFooter
50
+ right={
51
+ <Button
52
+ disabled={!isContinueEnabled}
53
+ leadingIcon={<span aria-hidden>✨</span>}
54
+ trailingIcon={<span aria-hidden>→</span>}
55
+ onClick={() => navigateToPath(ONBOARDING_STEPS[0].path)}
56
+ >
57
+ Vygenerovat draft booku
58
+ </Button>
59
+ }
60
+ />
61
+ </StepCard>
62
+ </div>
63
+ );
64
+ }
@@ -0,0 +1,41 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import { cn } from '../../lib/cn';
4
+
5
+ export type BadgeTone = 'neutral' | 'accent' | 'success' | 'warning' | 'error';
6
+
7
+ type BadgeProps = {
8
+ readonly tone?: BadgeTone;
9
+ /** Renders a small leading status dot. */
10
+ readonly dot?: boolean;
11
+ readonly children: ReactNode;
12
+ readonly className?: string;
13
+ };
14
+
15
+ const TONES: Record<BadgeTone, { chip: string; dot: string }> = {
16
+ neutral: { chip: 'bg-zinc-100 text-zinc-600', dot: 'bg-zinc-400' },
17
+ accent: {
18
+ chip: 'bg-[color:var(--ob-accent-50)] text-[color:var(--ob-accent-700)] ring-1 ring-inset ring-[color:var(--ob-accent-100)]',
19
+ dot: 'bg-[color:var(--ob-accent-500)]',
20
+ },
21
+ success: { chip: 'bg-emerald-100 text-emerald-700', dot: 'bg-emerald-500' },
22
+ warning: { chip: 'bg-amber-100 text-amber-700', dot: 'bg-amber-500' },
23
+ error: { chip: 'bg-red-100 text-red-700', dot: 'bg-red-500' },
24
+ };
25
+
26
+ /** Compact status pill / chip. */
27
+ export function Badge({ tone = 'neutral', dot = false, children, className }: BadgeProps) {
28
+ const t = TONES[tone];
29
+ return (
30
+ <span
31
+ className={cn(
32
+ 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',
33
+ t.chip,
34
+ className,
35
+ )}
36
+ >
37
+ {dot && <span className={cn('h-1.5 w-1.5 rounded-full', t.dot)} aria-hidden />}
38
+ {children}
39
+ </span>
40
+ );
41
+ }
@@ -0,0 +1,69 @@
1
+ import type { ReactNode } from 'react';
2
+
3
+ import { cn } from '../../lib/cn';
4
+
5
+ export type BannerTone = 'info' | 'success' | 'warning' | 'error';
6
+
7
+ type BannerProps = {
8
+ readonly tone?: BannerTone;
9
+ /** Optional bold heading shown above the body. */
10
+ readonly title?: ReactNode;
11
+ readonly children?: ReactNode;
12
+ /** Override the default emoji/icon for the tone. Pass `null` to hide it. */
13
+ readonly icon?: ReactNode;
14
+ readonly className?: string;
15
+ };
16
+
17
+ const TONES: Record<BannerTone, { wrap: string; icon: string; title: string; defaultIcon: string }> = {
18
+ info: {
19
+ wrap: 'border-[color:var(--ob-accent-200)] bg-[color:var(--ob-accent-50)] text-[color:var(--ob-accent-900)]',
20
+ icon: 'text-[color:var(--ob-accent-600)]',
21
+ title: 'text-[color:var(--ob-accent-900)]',
22
+ defaultIcon: 'ℹ️',
23
+ },
24
+ success: {
25
+ wrap: 'border-emerald-200 bg-emerald-50 text-emerald-800',
26
+ icon: 'text-emerald-600',
27
+ title: 'text-emerald-900',
28
+ defaultIcon: '✓',
29
+ },
30
+ warning: {
31
+ wrap: 'border-amber-200 bg-amber-50 text-amber-800',
32
+ icon: 'text-amber-600',
33
+ title: 'text-amber-900',
34
+ defaultIcon: '⚠️',
35
+ },
36
+ error: {
37
+ wrap: 'border-red-200 bg-red-50 text-red-800',
38
+ icon: 'text-red-600',
39
+ title: 'text-red-900',
40
+ defaultIcon: '⚠️',
41
+ },
42
+ };
43
+
44
+ /** Inline contextual message — info / success / warning / error. */
45
+ export function Banner({ tone = 'info', title, children, icon, className }: BannerProps) {
46
+ const t = TONES[tone];
47
+ const isIconShown = icon !== null;
48
+ return (
49
+ <div
50
+ role={tone === 'error' || tone === 'warning' ? 'alert' : 'status'}
51
+ className={cn(
52
+ 'flex gap-3 rounded-xl border px-4 py-3 text-sm leading-relaxed',
53
+ 'shadow-[var(--ob-shadow-xs)]',
54
+ t.wrap,
55
+ className,
56
+ )}
57
+ >
58
+ {isIconShown && (
59
+ <span className={cn('mt-px shrink-0 text-base leading-none', t.icon)} aria-hidden>
60
+ {icon ?? t.defaultIcon}
61
+ </span>
62
+ )}
63
+ <div className="min-w-0">
64
+ {title && <div className={cn('font-semibold', t.title)}>{title}</div>}
65
+ {children && <div className={cn(Boolean(title) && 'mt-0.5 opacity-90')}>{children}</div>}
66
+ </div>
67
+ </div>
68
+ );
69
+ }
@@ -0,0 +1,77 @@
1
+ import type { ButtonHTMLAttributes, ReactNode } from 'react';
2
+
3
+ import { cn } from '../../lib/cn';
4
+ import { Spinner } from './Spinner';
5
+ import { FOCUS_RING } from './tokens';
6
+
7
+ export type ButtonVariant = 'primary' | 'outline' | 'ghost' | 'inverted';
8
+ export type ButtonSize = 'md' | 'sm';
9
+
10
+ type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
11
+ readonly variant?: ButtonVariant;
12
+ readonly size?: ButtonSize;
13
+ /** When true, shows a spinner and disables the button (additive — defaults to false). */
14
+ readonly isLoading?: boolean;
15
+ /** Optional icon rendered before the label. */
16
+ readonly leadingIcon?: ReactNode;
17
+ /** Optional icon rendered after the label. */
18
+ readonly trailingIcon?: ReactNode;
19
+ };
20
+
21
+ const BASE =
22
+ 'inline-flex select-none items-center justify-center gap-2 rounded-xl font-semibold ' +
23
+ 'transition-[box-shadow,transform,filter,color,border-color,background-color] duration-150 ease-out ' +
24
+ 'active:translate-y-px disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-45 ' +
25
+ FOCUS_RING;
26
+
27
+ const VARIANTS: Record<ButtonVariant, string> = {
28
+ primary:
29
+ 'text-[color:var(--ob-ink)] bg-[image:var(--ob-grad-primary)] ' +
30
+ 'shadow-[var(--ob-shadow-accent)] hover:shadow-[var(--ob-shadow-lg)] hover:brightness-[1.04] active:brightness-95',
31
+ outline:
32
+ 'border border-zinc-200/80 bg-white text-zinc-700 shadow-[var(--ob-shadow-xs)] ' +
33
+ 'hover:border-zinc-300 hover:bg-zinc-50 hover:text-zinc-900 active:bg-zinc-100',
34
+ ghost: 'text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 active:bg-zinc-200/70',
35
+ inverted:
36
+ 'bg-white text-[color:var(--ob-accent-700)] shadow-[var(--ob-shadow-sm)] ' +
37
+ 'hover:bg-white/90 active:bg-white/80',
38
+ };
39
+
40
+ const SIZES: Record<ButtonSize, string> = {
41
+ md: 'h-10 px-5 text-sm',
42
+ sm: 'h-8 px-3.5 text-[13px]',
43
+ };
44
+
45
+ export function Button({
46
+ variant = 'primary',
47
+ size = 'md',
48
+ isLoading = false,
49
+ leadingIcon,
50
+ trailingIcon,
51
+ className,
52
+ type = 'button',
53
+ disabled,
54
+ children,
55
+ ...props
56
+ }: ButtonProps) {
57
+ const spinnerSize = size === 'sm' ? 'h-3.5 w-3.5' : 'h-4 w-4';
58
+ return (
59
+ <button
60
+ type={type}
61
+ disabled={disabled || isLoading}
62
+ aria-busy={isLoading || undefined}
63
+ className={cn(BASE, VARIANTS[variant], SIZES[size], className)}
64
+ {...props}
65
+ >
66
+ {isLoading ? (
67
+ <Spinner className={cn(spinnerSize, variant === 'primary' && 'border-white/40 border-t-white')} />
68
+ ) : (
69
+ leadingIcon && <span className="-ml-0.5 inline-flex shrink-0 items-center">{leadingIcon}</span>
70
+ )}
71
+ {children}
72
+ {!isLoading && trailingIcon && (
73
+ <span className="-mr-0.5 inline-flex shrink-0 items-center">{trailingIcon}</span>
74
+ )}
75
+ </button>
76
+ );
77
+ }
@@ -0,0 +1,33 @@
1
+ import type { HTMLAttributes } from 'react';
2
+
3
+ import { cn } from '../../lib/cn';
4
+ import { FOCUS_RING } from './tokens';
5
+
6
+ export type CardVariant = 'default' | 'elevated' | 'interactive';
7
+
8
+ type CardProps = HTMLAttributes<HTMLDivElement> & {
9
+ /** Visual weight. `elevated` lifts off the page; `interactive` adds hover feedback. */
10
+ readonly variant?: CardVariant;
11
+ };
12
+
13
+ const VARIANTS: Record<CardVariant, string> = {
14
+ default: 'shadow-[var(--ob-shadow-sm)]',
15
+ elevated: 'shadow-[var(--ob-shadow-lg)]',
16
+ interactive:
17
+ 'shadow-[var(--ob-shadow-sm)] cursor-pointer transition-[box-shadow,border-color,transform] ' +
18
+ 'duration-200 hover:-translate-y-0.5 hover:border-[color:var(--ob-accent-200)] hover:shadow-[var(--ob-shadow-md)] ' +
19
+ FOCUS_RING,
20
+ };
21
+
22
+ export function Card({ variant = 'default', className, ...props }: CardProps) {
23
+ return (
24
+ <div
25
+ className={cn(
26
+ 'rounded-2xl border border-zinc-200/60 bg-white',
27
+ VARIANTS[variant],
28
+ className,
29
+ )}
30
+ {...props}
31
+ />
32
+ );
33
+ }
@@ -0,0 +1,103 @@
1
+ import { useId } from 'react';
2
+ import type { InputHTMLAttributes, ReactNode, TextareaHTMLAttributes } from 'react';
3
+
4
+ import { cn } from '../../lib/cn';
5
+ import { FOCUS_RING_INPUT } from './tokens';
6
+
7
+ /**
8
+ * Shared control styling for text inputs / textareas. Exported so hand-rolled inputs
9
+ * elsewhere in the module (URL field, chat composer) stay visually identical — DRY.
10
+ */
11
+ export const CONTROL =
12
+ 'w-full rounded-xl border border-zinc-300 bg-white px-3.5 py-2.5 text-sm text-zinc-900 ' +
13
+ 'shadow-[var(--ob-shadow-xs)] placeholder:text-zinc-400 transition-[border-color,box-shadow] ' +
14
+ 'disabled:cursor-not-allowed disabled:bg-zinc-50 disabled:text-zinc-400 ' +
15
+ FOCUS_RING_INPUT;
16
+
17
+ /** Applied on top of CONTROL when a field is in an error state. */
18
+ export const CONTROL_ERROR =
19
+ 'border-red-300 focus:border-red-400 focus:ring-red-500/15';
20
+
21
+ type FieldShellProps = {
22
+ readonly label: string;
23
+ readonly hint?: ReactNode;
24
+ readonly htmlFor: string;
25
+ readonly children: ReactNode;
26
+ readonly labelSuffix?: ReactNode;
27
+ readonly error?: ReactNode;
28
+ readonly describedById?: string;
29
+ };
30
+
31
+ function FieldShell({ label, hint, htmlFor, children, labelSuffix, error, describedById }: FieldShellProps) {
32
+ return (
33
+ <div className="space-y-1.5">
34
+ <label htmlFor={htmlFor} className="flex items-center gap-2 text-[13px] font-semibold text-zinc-700">
35
+ {label}
36
+ {labelSuffix}
37
+ </label>
38
+ {children}
39
+ {error ? (
40
+ <p id={describedById} className="flex items-center gap-1.5 text-xs font-medium text-red-600">
41
+ <svg viewBox="0 0 16 16" className="h-3.5 w-3.5 shrink-0" fill="currentColor" aria-hidden>
42
+ <path d="M8 1.5a6.5 6.5 0 100 13 6.5 6.5 0 000-13zM7.25 5a.75.75 0 011.5 0v3.5a.75.75 0 01-1.5 0V5zM8 10.25a.9.9 0 100 1.8.9.9 0 000-1.8z" />
43
+ </svg>
44
+ {error}
45
+ </p>
46
+ ) : (
47
+ hint && (
48
+ <p id={describedById} className="text-xs leading-relaxed text-zinc-400">
49
+ {hint}
50
+ </p>
51
+ )
52
+ )}
53
+ </div>
54
+ );
55
+ }
56
+
57
+ type InputFieldProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'id'> & {
58
+ readonly label: string;
59
+ readonly hint?: ReactNode;
60
+ readonly labelSuffix?: ReactNode;
61
+ /** When set, the control turns red and this message replaces the hint. Additive. */
62
+ readonly error?: ReactNode;
63
+ };
64
+
65
+ export function InputField({ label, hint, labelSuffix, error, className, ...props }: InputFieldProps) {
66
+ const id = useId();
67
+ const descId = `${id}-desc`;
68
+ return (
69
+ <FieldShell label={label} hint={hint} htmlFor={id} labelSuffix={labelSuffix} error={error} describedById={descId}>
70
+ <input
71
+ id={id}
72
+ aria-invalid={error ? true : undefined}
73
+ aria-describedby={error || hint ? descId : undefined}
74
+ className={cn(CONTROL, Boolean(error) && CONTROL_ERROR, className)}
75
+ {...props}
76
+ />
77
+ </FieldShell>
78
+ );
79
+ }
80
+
81
+ type TextareaFieldProps = Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'id'> & {
82
+ readonly label: string;
83
+ readonly hint?: ReactNode;
84
+ readonly labelSuffix?: ReactNode;
85
+ /** When set, the control turns red and this message replaces the hint. Additive. */
86
+ readonly error?: ReactNode;
87
+ };
88
+
89
+ export function TextareaField({ label, hint, labelSuffix, error, className, ...props }: TextareaFieldProps) {
90
+ const id = useId();
91
+ const descId = `${id}-desc`;
92
+ return (
93
+ <FieldShell label={label} hint={hint} htmlFor={id} labelSuffix={labelSuffix} error={error} describedById={descId}>
94
+ <textarea
95
+ id={id}
96
+ aria-invalid={error ? true : undefined}
97
+ aria-describedby={error || hint ? descId : undefined}
98
+ className={cn(CONTROL, 'resize-y', Boolean(error) && CONTROL_ERROR, className)}
99
+ {...props}
100
+ />
101
+ </FieldShell>
102
+ );
103
+ }