@promptbook/cli 0.114.0-1 → 0.114.0-2

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 (113) hide show
  1. package/README.md +16 -15
  2. package/apps/agents-server/package.json +6 -4
  3. package/apps/agents-server/playwright.config.ts +28 -38
  4. package/apps/agents-server/scripts/build-agents-server.js +62 -0
  5. package/apps/agents-server/scripts/build-e2e.js +38 -0
  6. package/apps/agents-server/scripts/ensure-root-dependencies.js +86 -0
  7. package/apps/agents-server/scripts/prerender-homepage.js +1 -1
  8. package/apps/agents-server/scripts/run-e2e-tests.js +34 -0
  9. package/apps/agents-server/scripts/run-npm.js +42 -0
  10. package/apps/agents-server/src/app/admin/email-server/page.tsx +14 -6
  11. package/apps/agents-server/src/app/api/elevenlabs/tts/route.ts +3 -3
  12. package/apps/agents-server/src/app/api/onboarding/book/route.ts +7 -6
  13. package/apps/agents-server/src/app/superadmin/servers/ServersRegistryTable.tsx +105 -102
  14. package/apps/agents-server/src/app/superadmin/servers/useServersRegistryState.ts +15 -7
  15. package/apps/agents-server/src/components/AgentProjectDnsInstructions/AgentProjectDnsInstructions.tsx +11 -11
  16. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ManGoBookEditor.tsx +82 -0
  17. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +2 -2
  18. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +13 -16
  19. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +4 -4
  20. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +23 -16
  21. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/bookSource.ts +54 -0
  22. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +15 -8
  23. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +3 -37
  24. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoOpenEditorRequest.ts +1 -1
  25. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +2 -2
  26. package/apps/agents-server/src/components/UsersList/CreateUserDialog.tsx +13 -22
  27. package/apps/agents-server/src/components/UsersList/PasswordGeneratorDialog.tsx +216 -0
  28. package/apps/agents-server/src/components/UsersList/UsersList.tsx +16 -11
  29. package/apps/agents-server/src/components/UsersList/generateSecurePassword.ts +112 -24
  30. package/apps/agents-server/src/components/UsersList/userDialogClassNames.ts +11 -0
  31. package/apps/agents-server/src/languages/ServerTranslationKeys.ts +11 -0
  32. package/apps/agents-server/src/languages/translations/czech.yaml +11 -0
  33. package/apps/agents-server/src/languages/translations/english.yaml +11 -0
  34. package/apps/agents-server/src/utils/agentProjects/agentProjectHrefs.ts +11 -0
  35. package/apps/agents-server/src/utils/agentProjects/createAgentProjectDnsRecords.ts +53 -7
  36. package/apps/agents-server/src/utils/agentProjects/createAgentProjectMarkdownReferences.ts +37 -27
  37. package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentBooks.ts +2 -13
  38. package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentRuntime.ts +21 -73
  39. package/apps/agents-server/src/utils/stalwart/createEmailDnsInstructions.ts +9 -5
  40. package/apps/agents-server/src/utils/stalwart/readStalwartEmailSnapshot.ts +23 -5
  41. package/apps/agents-server/src/utils/stalwart/stalwartBootstrap.ts +2 -1
  42. package/apps/agents-server/src/utils/stalwart/stalwartMailBridge.ts +7 -0
  43. package/apps/agents-server/tests/e2e/e2eEnvironment.cjs +49 -0
  44. package/esm/index.es.js +523 -169
  45. package/esm/index.es.js.map +1 -1
  46. package/esm/scripts/run-agent-chat/runCoderPing.d.ts +48 -0
  47. package/esm/scripts/run-codex-prompts/prompts/findNextTodoPrompt.d.ts +2 -1
  48. package/esm/scripts/run-codex-prompts/prompts/isPromptCompatibleWithRunner.d.ts +27 -0
  49. package/esm/scripts/run-codex-prompts/prompts/listRunnablePrompts.d.ts +2 -1
  50. package/esm/scripts/run-codex-prompts/prompts/listUpcomingTasks.d.ts +2 -1
  51. package/esm/scripts/run-codex-prompts/prompts/replacePromptTodoStatusLine.d.ts +7 -0
  52. package/esm/scripts/run-codex-prompts/testing/TestBeforeMode.d.ts +16 -0
  53. package/esm/scripts/run-codex-prompts/testing/createTestBeforeRepairPrompt.d.ts +9 -0
  54. package/esm/scripts/run-codex-prompts/testing/limitTestOutput.d.ts +4 -0
  55. package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -2
  56. package/esm/scripts/run-codex-prompts/testing/runTestBefore.d.ts +24 -0
  57. package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -0
  58. package/esm/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.d.ts +1 -15
  59. package/esm/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.d.ts +1 -1
  60. package/esm/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.d.ts +0 -4
  61. package/esm/src/book-components/Chat/utils/renderMarkdown.d.ts +7 -0
  62. package/esm/src/cli/cli-commands/coder/agentCodingFile.d.ts +2 -3
  63. package/esm/src/cli/cli-commands/coder/ping.d.ts +13 -0
  64. package/esm/src/cli/cli-commands/coder/ping.test.d.ts +1 -0
  65. package/esm/src/cli/cli-commands/coder.d.ts +1 -0
  66. package/package.json +1 -1
  67. package/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.ts +1 -15
  68. package/src/book-2.0/book-language-documentation/bookLanguageDocumentationExamples.ts +1 -2
  69. package/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.ts +92 -32
  70. package/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.ts +16 -39
  71. package/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.ts +16 -36
  72. package/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.ts +9 -1
  73. package/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.ts +4 -51
  74. package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +291 -4
  75. package/src/book-components/Chat/utils/renderMarkdown.ts +133 -9
  76. package/src/cli/cli-commands/agents-server/startAgentsServer/createLocalAgentRunOptions.ts +1 -0
  77. package/src/cli/cli-commands/coder/agentCodingFile.ts +6 -129
  78. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  79. package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +1 -4
  80. package/src/cli/cli-commands/coder/ping.ts +94 -0
  81. package/src/cli/cli-commands/coder/run.ts +25 -2
  82. package/src/cli/cli-commands/coder.ts +4 -0
  83. package/src/other/templates/getTemplatesPipelineCollection.ts +835 -738
  84. package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +101 -0
  85. package/src/version.ts +1 -1
  86. package/src/versions.txt +1 -1
  87. package/umd/index.umd.js +525 -171
  88. package/umd/index.umd.js.map +1 -1
  89. package/umd/scripts/run-agent-chat/runCoderPing.d.ts +48 -0
  90. package/umd/scripts/run-codex-prompts/prompts/findNextTodoPrompt.d.ts +2 -1
  91. package/umd/scripts/run-codex-prompts/prompts/isPromptCompatibleWithRunner.d.ts +27 -0
  92. package/umd/scripts/run-codex-prompts/prompts/listRunnablePrompts.d.ts +2 -1
  93. package/umd/scripts/run-codex-prompts/prompts/listUpcomingTasks.d.ts +2 -1
  94. package/umd/scripts/run-codex-prompts/prompts/replacePromptTodoStatusLine.d.ts +7 -0
  95. package/umd/scripts/run-codex-prompts/testing/TestBeforeMode.d.ts +16 -0
  96. package/umd/scripts/run-codex-prompts/testing/createTestBeforeRepairPrompt.d.ts +9 -0
  97. package/umd/scripts/run-codex-prompts/testing/limitTestOutput.d.ts +4 -0
  98. package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -2
  99. package/umd/scripts/run-codex-prompts/testing/runTestBefore.d.ts +24 -0
  100. package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -0
  101. package/umd/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.d.ts +1 -15
  102. package/umd/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.d.ts +1 -1
  103. package/umd/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.d.ts +0 -4
  104. package/umd/src/book-components/Chat/utils/renderMarkdown.d.ts +7 -0
  105. package/umd/src/cli/cli-commands/coder/agentCodingFile.d.ts +2 -3
  106. package/umd/src/cli/cli-commands/coder/ping.d.ts +13 -0
  107. package/umd/src/cli/cli-commands/coder/ping.test.d.ts +1 -0
  108. package/umd/src/cli/cli-commands/coder.d.ts +1 -0
  109. package/apps/agents-server/src/app/api/onboarding/draft/route.ts +0 -23
  110. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +0 -125
  111. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +0 -154
  112. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +0 -188
  113. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +0 -32
@@ -1,50 +1,138 @@
1
1
  /**
2
- * Default length of passwords generated for new admin users.
2
+ * Configuration for a generated password.
3
+ *
4
+ * @private utility of <PasswordGeneratorDialog/>
5
+ */
6
+ export type PasswordGeneratorOptions = {
7
+ readonly length: number;
8
+ readonly isUppercaseLettersIncluded: boolean;
9
+ readonly isLowercaseLettersIncluded: boolean;
10
+ readonly isNumbersIncluded: boolean;
11
+ readonly isSpecialCharactersIncluded: boolean;
12
+ };
13
+
14
+ /**
15
+ * Names of the configurable character categories.
16
+ *
17
+ * @private utility of <PasswordGeneratorDialog/>
3
18
  */
4
- const GENERATED_PASSWORD_LENGTH = 20;
19
+ export type PasswordCharacterOptionName = Exclude<keyof PasswordGeneratorOptions, 'length'>;
5
20
 
6
21
  /**
7
- * Characters used by generated passwords.
22
+ * Default configuration for securely generated passwords.
23
+ *
24
+ * @private utility of <PasswordGeneratorDialog/>
8
25
  */
9
- const GENERATED_PASSWORD_CHARACTERS = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789!@#$%^&*+-_=~';
26
+ export const DEFAULT_PASSWORD_GENERATOR_OPTIONS: PasswordGeneratorOptions = {
27
+ length: 16,
28
+ isUppercaseLettersIncluded: true,
29
+ isLowercaseLettersIncluded: true,
30
+ isNumbersIncluded: true,
31
+ isSpecialCharactersIncluded: true,
32
+ };
33
+
34
+ /**
35
+ * Character categories that can be included in a generated password.
36
+ *
37
+ * @private utility of <PasswordGeneratorDialog/>
38
+ */
39
+ export const PASSWORD_CHARACTER_OPTION_NAMES: ReadonlyArray<PasswordCharacterOptionName> = [
40
+ 'isUppercaseLettersIncluded',
41
+ 'isLowercaseLettersIncluded',
42
+ 'isNumbersIncluded',
43
+ 'isSpecialCharactersIncluded',
44
+ ];
45
+
46
+ /**
47
+ * Character sets used for the configurable password categories.
48
+ */
49
+ const PASSWORD_CHARACTERS_BY_OPTION_NAME: Readonly<Record<PasswordCharacterOptionName, string>> = {
50
+ isUppercaseLettersIncluded: 'ABCDEFGHJKLMNPQRSTUVWXYZ',
51
+ isLowercaseLettersIncluded: 'abcdefghijkmnopqrstuvwxyz',
52
+ isNumbersIncluded: '23456789',
53
+ isSpecialCharactersIncluded: '!@#$%^&*+-_=~',
54
+ };
55
+
56
+ /**
57
+ * Obtains one unbiased random index from a character set using the browser Web Crypto API.
58
+ *
59
+ * @private utility of generateSecurePassword
60
+ */
61
+ function getSecureRandomIndex(secureRandomSource: Crypto, characterCount: number): number {
62
+ const largestAcceptableRandomValue = Math.floor(0x1_0000_0000 / characterCount) * characterCount;
63
+ const randomValues = new Uint32Array(1);
64
+
65
+ let randomValue: number | undefined;
66
+
67
+ do {
68
+ secureRandomSource.getRandomValues(randomValues);
69
+ randomValue = randomValues[0];
70
+ } while (randomValue === undefined || randomValue >= largestAcceptableRandomValue);
71
+
72
+ return randomValue % characterCount;
73
+ }
74
+
75
+ /**
76
+ * Randomly reorders password characters with the Fisher-Yates algorithm.
77
+ *
78
+ * @private utility of generateSecurePassword
79
+ */
80
+ function shufflePasswordCharacters(passwordCharacters: Array<string>, secureRandomSource: Crypto): void {
81
+ for (let index = passwordCharacters.length - 1; index > 0; index--) {
82
+ const randomIndex = getSecureRandomIndex(secureRandomSource, index + 1);
83
+ const currentPasswordCharacter = passwordCharacters[index];
84
+ const randomPasswordCharacter = passwordCharacters[randomIndex];
85
+
86
+ if (currentPasswordCharacter === undefined || randomPasswordCharacter === undefined) {
87
+ continue;
88
+ }
89
+
90
+ passwordCharacters[index] = randomPasswordCharacter;
91
+ passwordCharacters[randomIndex] = currentPasswordCharacter;
92
+ }
93
+ }
10
94
 
11
95
  /**
12
96
  * Generates a password using the browser Web Crypto API.
13
97
  *
14
- * Rejection sampling keeps every character equally likely even though the
15
- * alphabet length is not a power of two.
98
+ * Rejection sampling keeps every selected character equally likely even when
99
+ * the character-set length is not a power of two. Every selected character
100
+ * category is guaranteed to occur at least once.
16
101
  *
17
- * @returns A cryptographically random password, or an empty string when a secure random source is unavailable.
102
+ * @param options - Length and character categories to use for the password.
103
+ * @returns A cryptographically random password, or an empty string when the configuration is invalid or a secure random source is unavailable.
18
104
  *
19
- * @private utility of <CreateUserDialog/>
105
+ * @private utility of <PasswordGeneratorDialog/>
20
106
  */
21
- export function generateSecurePassword(): string {
107
+ export function generateSecurePassword(options: PasswordGeneratorOptions = DEFAULT_PASSWORD_GENERATOR_OPTIONS): string {
22
108
  const secureRandomSource = globalThis.crypto;
23
109
 
24
110
  if (!secureRandomSource?.getRandomValues) {
25
111
  return '';
26
112
  }
27
113
 
28
- const characterCount = GENERATED_PASSWORD_CHARACTERS.length;
29
- const largestAcceptableRandomValue = Math.floor(0x1_0000_0000 / characterCount) * characterCount;
30
- const passwordCharacters: Array<string> = [];
31
- const randomValues = new Uint32Array(64);
114
+ const characterSets = PASSWORD_CHARACTER_OPTION_NAMES.filter((optionName) => options[optionName]).map(
115
+ (optionName) => PASSWORD_CHARACTERS_BY_OPTION_NAME[optionName],
116
+ );
32
117
 
33
- while (passwordCharacters.length < GENERATED_PASSWORD_LENGTH) {
34
- secureRandomSource.getRandomValues(randomValues);
118
+ if (!Number.isSafeInteger(options.length) || options.length < characterSets.length || characterSets.length === 0) {
119
+ return '';
120
+ }
35
121
 
36
- for (const randomValue of randomValues) {
37
- if (randomValue >= largestAcceptableRandomValue) {
38
- continue;
39
- }
122
+ const allPasswordCharacters = characterSets.join('');
123
+ const passwordCharacters: Array<string> = [];
40
124
 
41
- passwordCharacters.push(GENERATED_PASSWORD_CHARACTERS.charAt(randomValue % characterCount));
125
+ for (const characterSet of characterSets) {
126
+ passwordCharacters.push(characterSet.charAt(getSecureRandomIndex(secureRandomSource, characterSet.length)));
127
+ }
42
128
 
43
- if (passwordCharacters.length === GENERATED_PASSWORD_LENGTH) {
44
- break;
45
- }
46
- }
129
+ while (passwordCharacters.length < options.length) {
130
+ passwordCharacters.push(
131
+ allPasswordCharacters.charAt(getSecureRandomIndex(secureRandomSource, allPasswordCharacters.length)),
132
+ );
47
133
  }
48
134
 
135
+ shufflePasswordCharacters(passwordCharacters, secureRandomSource);
136
+
49
137
  return passwordCharacters.join('');
50
138
  }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Shared secondary-button styling used by the user-management dialogs.
3
+ */
4
+ export const USER_DIALOG_SECONDARY_BUTTON_CLASS_NAME =
5
+ 'inline-flex items-center justify-center gap-2 rounded-md border border-gray-300 bg-white px-3 py-2 text-sm font-semibold text-gray-700 hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-60';
6
+
7
+ /**
8
+ * Shared primary-button styling used by the user-management dialogs.
9
+ */
10
+ export const USER_DIALOG_PRIMARY_BUTTON_CLASS_NAME =
11
+ 'inline-flex items-center justify-center gap-2 rounded-md bg-blue-600 px-3 py-2 text-sm font-semibold text-white hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-60';
@@ -437,7 +437,18 @@ export const SERVER_TRANSLATION_KEYS = [
437
437
  'users.passwordPlaceholder',
438
438
  'users.passwordAriaLabel',
439
439
  'users.generatePassword',
440
+ 'users.passwordGeneratorTitle',
441
+ 'users.closePasswordGeneratorDialog',
440
442
  'users.passwordGeneratorDescription',
443
+ 'users.passwordGeneratorLength',
444
+ 'users.passwordGeneratorCharacters',
445
+ 'users.passwordGeneratorIncludeUppercaseLetters',
446
+ 'users.passwordGeneratorIncludeLowercaseLetters',
447
+ 'users.passwordGeneratorIncludeNumbers',
448
+ 'users.passwordGeneratorIncludeSpecialCharacters',
449
+ 'users.generatedPassword',
450
+ 'users.regeneratePassword',
451
+ 'users.useGeneratedPassword',
441
452
  'users.isAdminCheckbox',
442
453
  'users.adminRoleDescription',
443
454
  'users.createUser',
@@ -431,7 +431,18 @@ users.passwordLabel: Heslo
431
431
  users.passwordPlaceholder: Heslo
432
432
  users.passwordAriaLabel: Heslo
433
433
  users.generatePassword: Vygenerovat bezpečné heslo
434
+ users.passwordGeneratorTitle: Generátor hesla
435
+ users.closePasswordGeneratorDialog: Zavřít generátor hesla
434
436
  users.passwordGeneratorDescription: Používá bezpečný generátor náhodných hodnot vašeho prohlížeče.
437
+ users.passwordGeneratorLength: Délka hesla
438
+ users.passwordGeneratorCharacters: Zahrnout znaky
439
+ users.passwordGeneratorIncludeUppercaseLetters: Zahrnout velká písmena
440
+ users.passwordGeneratorIncludeLowercaseLetters: Zahrnout malá písmena
441
+ users.passwordGeneratorIncludeNumbers: Zahrnout čísla
442
+ users.passwordGeneratorIncludeSpecialCharacters: Zahrnout speciální znaky
443
+ users.generatedPassword: Vygenerované heslo
444
+ users.regeneratePassword: Vygenerovat jiné heslo
445
+ users.useGeneratedPassword: Použít vygenerované heslo
435
446
  users.isAdminCheckbox: Administrátor
436
447
  users.adminRoleDescription: Správci mohou spravovat tento server a jeho uživatele.
437
448
  users.createUser: Vytvořit uživatele
@@ -435,7 +435,18 @@ users.passwordLabel: Password
435
435
  users.passwordPlaceholder: Password
436
436
  users.passwordAriaLabel: Password
437
437
  users.generatePassword: Generate secure password
438
+ users.passwordGeneratorTitle: Password generator
439
+ users.closePasswordGeneratorDialog: Close password generator
438
440
  users.passwordGeneratorDescription: Uses your browser's secure random generator.
441
+ users.passwordGeneratorLength: Password length
442
+ users.passwordGeneratorCharacters: Include characters
443
+ users.passwordGeneratorIncludeUppercaseLetters: Include uppercase letters
444
+ users.passwordGeneratorIncludeLowercaseLetters: Include lowercase letters
445
+ users.passwordGeneratorIncludeNumbers: Include numbers
446
+ users.passwordGeneratorIncludeSpecialCharacters: Include special characters
447
+ users.generatedPassword: Generated password
448
+ users.regeneratePassword: Generate another password
449
+ users.useGeneratedPassword: Use generated password
439
450
  users.isAdminCheckbox: Is Admin
440
451
  users.adminRoleDescription: Administrators can manage this server and its users.
441
452
  users.createUser: Create User
@@ -43,6 +43,17 @@ export function buildAgentProjectProfileHref(agentPermanentId: string, projectNa
43
43
  return `${buildAgentProjectsDashboardHref(agentPermanentId)}/${encodeURIComponent(projectName)}`;
44
44
  }
45
45
 
46
+ /**
47
+ * Builds the href prefix serving files from one agent project.
48
+ *
49
+ * @param agentPermanentId - Permanent id of the agent.
50
+ * @param projectName - Project directory name.
51
+ * @returns Project file href prefix.
52
+ */
53
+ export function buildAgentProjectFilesHrefPrefix(agentPermanentId: string, projectName: string): string {
54
+ return `${buildAgentProjectProfileHref(agentPermanentId, projectName)}/files/`;
55
+ }
56
+
46
57
  /**
47
58
  * Builds the href of one project on its owning server.
48
59
  *
@@ -33,19 +33,52 @@ export type AgentProjectDnsRecord = {
33
33
  };
34
34
 
35
35
  /**
36
- * Creates the one DNS record shown for a selected project-domain setup.
36
+ * Placeholder used when preventive project DNS guidance has no assigned project domain yet.
37
37
  *
38
- * @param options - Project domain, server domain, and selected DNS variants.
39
- * @returns One DNS record instruction.
38
+ * @private helper for the Agents Server project DNS instructions
39
+ */
40
+ const PROJECT_DOMAIN_NAME_PLACEHOLDER = '<PROJECT_NAME>';
41
+
42
+ /**
43
+ * Inputs used to create one project DNS record instruction.
44
+ *
45
+ * @private helper for the Agents Server project DNS instructions
40
46
  */
41
- export function createAgentProjectDnsRecord(options: {
47
+ type CreateAgentProjectDnsRecordOptions = {
48
+ /**
49
+ * Whether the resulting DNS record should be a CNAME instead of an A record.
50
+ */
42
51
  readonly isCnameRecord: boolean;
52
+
53
+ /**
54
+ * Whether the resulting DNS record should cover every generated project domain.
55
+ */
43
56
  readonly isWildcardDomain: boolean;
44
- readonly projectDomain: string;
57
+
58
+ /**
59
+ * Assigned project hostname used by the single-project variant, when available.
60
+ */
61
+ readonly projectDomain?: string | null;
62
+
63
+ /**
64
+ * Public VPS IP address used by the A-record variant, when known.
65
+ */
45
66
  readonly publicIpAddress: string | null | undefined;
67
+
68
+ /**
69
+ * Base server domain used by generated project hostnames.
70
+ */
46
71
  readonly serverDomain: string;
47
- }): AgentProjectDnsRecord {
48
- const name = options.isWildcardDomain ? `*.${options.serverDomain}` : options.projectDomain;
72
+ };
73
+
74
+ /**
75
+ * Creates the one DNS record shown for a selected project-domain setup.
76
+ *
77
+ * @param options - Project domain, server domain, and selected DNS variants.
78
+ * @returns One DNS record instruction.
79
+ */
80
+ export function createAgentProjectDnsRecord(options: CreateAgentProjectDnsRecordOptions): AgentProjectDnsRecord {
81
+ const name = createAgentProjectDnsRecordName(options);
49
82
 
50
83
  if (options.isCnameRecord) {
51
84
  return {
@@ -65,3 +98,16 @@ export function createAgentProjectDnsRecord(options: {
65
98
  : 'Replace <VPS_PUBLIC_IP> with the public IP address of this VPS.',
66
99
  };
67
100
  }
101
+
102
+ /**
103
+ * Resolves the DNS hostname displayed for one project DNS record instruction.
104
+ *
105
+ * @private helper for createAgentProjectDnsRecord
106
+ */
107
+ function createAgentProjectDnsRecordName(options: CreateAgentProjectDnsRecordOptions): string {
108
+ if (options.isWildcardDomain) {
109
+ return `*.${options.serverDomain}`;
110
+ }
111
+
112
+ return options.projectDomain || `${PROJECT_DOMAIN_NAME_PLACEHOLDER}.${options.serverDomain}`;
113
+ }
@@ -1,6 +1,6 @@
1
1
  import type { MarkdownInlineReference } from '@promptbook-local/types';
2
2
  import type { AgentProjectReferenceInfo } from './AgentProjectReferenceInfo';
3
- import { buildAgentProjectProfileHref } from './agentProjectHrefs';
3
+ import { buildAgentProjectFilesHrefPrefix, buildAgentProjectProfileHref } from './agentProjectHrefs';
4
4
 
5
5
  /**
6
6
  * Markdown inline reference data consumed by chat markdown rendering.
@@ -39,31 +39,41 @@ type AgentProjectMarkdownReferenceInfo = Pick<
39
39
  export function createAgentProjectMarkdownReferences(
40
40
  options: CreateAgentProjectMarkdownReferencesOptions,
41
41
  ): ReadonlyArray<AgentProjectMarkdownReference> {
42
- return options.projects.map((project) => ({
43
- reference: project.projectName,
44
- label: project.displayName || project.projectName,
45
- href: buildAgentProjectProfileHref(options.agentPermanentId, project.projectName),
46
- title: project.description || project.displayName || project.projectName,
47
- menu: {
48
- status: {
49
- label: project.isRunning ? 'Project is running' : 'Project is not running',
50
- isActive: project.isRunning ?? false,
51
- },
52
- options: [
53
- {
54
- label: 'Open the project in a new tab',
55
- href: project.isRunning ? project.projectUrl ?? null : null,
56
- title:
57
- project.isRunning && project.projectUrl
58
- ? 'Open the project in a new tab'
59
- : 'The project must run before it can be opened.',
60
- },
61
- {
62
- label: 'Open the project page in a new tab',
63
- href: buildAgentProjectProfileHref(options.agentPermanentId, project.projectName),
64
- title: 'Open the project page in a new tab',
65
- },
42
+ return options.projects.map((project) => {
43
+ const projectProfileHref = buildAgentProjectProfileHref(options.agentPermanentId, project.projectName);
44
+ const projectUrl = project.projectUrl || null;
45
+
46
+ return {
47
+ reference: project.projectName,
48
+ label: project.displayName || project.projectName,
49
+ href: projectProfileHref,
50
+ sourceHrefPrefixes: [
51
+ projectProfileHref,
52
+ buildAgentProjectFilesHrefPrefix(options.agentPermanentId, project.projectName),
53
+ ...(projectUrl ? [projectUrl] : []),
66
54
  ],
67
- },
68
- }));
55
+ title: project.description || project.displayName || project.projectName,
56
+ menu: {
57
+ status: {
58
+ label: project.isRunning ? 'Project is running' : 'Project is not running',
59
+ isActive: project.isRunning ?? false,
60
+ },
61
+ options: [
62
+ {
63
+ label: 'Open the project in a new tab',
64
+ href: project.isRunning ? projectUrl : null,
65
+ title:
66
+ project.isRunning && projectUrl
67
+ ? 'Open the project in a new tab'
68
+ : 'The project must run before it can be opened.',
69
+ },
70
+ {
71
+ label: 'Open the project page in a new tab',
72
+ href: projectProfileHref,
73
+ title: 'Open the project page in a new tab',
74
+ },
75
+ ],
76
+ },
77
+ };
78
+ });
69
79
  }
@@ -1,18 +1,7 @@
1
1
  import { spaceTrim } from 'spacetrim';
2
2
 
3
3
  /**
4
- * Agent book copied from the manGo onboarding experiment and used as the drafting specialist.
5
- *
6
- * @private internal constant of manGo onboarding agent utilities
7
- */
8
- export const MAN_GO_DRAFT_EXPERT_BOOK = spaceTrim(`
9
- Book language expert
10
-
11
- LANGUAGE Čeština
12
- `);
13
-
14
- /**
15
- * Agent book copied from the manGo onboarding experiment and used to convert free-form drafts to Book language.
4
+ * Agent book copied from the manGo onboarding experiment and used to generate Book language directly.
16
5
  *
17
6
  * @private internal constant of manGo onboarding agent utilities
18
7
  */
@@ -22,7 +11,7 @@ export const MAN_GO_BOOK_EXPERT_BOOK = spaceTrim(`
22
11
  PERSONA You are expert in book language
23
12
  RULE You can work with the book language and write, modify, or consult the agents based on the book language.
24
13
 
25
- KNOWLEDGE https://core.ptbk.io/api/docs/book-language.md
14
+ KNOWLEDGE https://live.ptbk.io/api/docs/book-language.md?language=en
26
15
 
27
16
  RULE When creating agents, use code blocks with book language:
28
17
 
@@ -5,11 +5,7 @@ import { LiteAgent } from '../../../../../src/book-3.0/LiteAgent';
5
5
  import type { string_markdown } from '../../../../../src/types/string_markdown';
6
6
  import { validateBook } from '../../../../../src/book-2.0/agent-source/string_book';
7
7
  import { spaceTrim } from 'spacetrim';
8
- import {
9
- MAN_GO_BOOK_EXPERT_BOOK,
10
- MAN_GO_DRAFT_EXPERT_BOOK,
11
- MAN_GO_REPLY_REVIEWER_BOOK,
12
- } from './manGoOnboardingAgentBooks';
8
+ import { MAN_GO_BOOK_EXPERT_BOOK, MAN_GO_REPLY_REVIEWER_BOOK } from './manGoOnboardingAgentBooks';
13
9
 
14
10
  /**
15
11
  * Chat message accepted by the manGo onboarding test runner.
@@ -36,20 +32,13 @@ export type ManGoOnboardingReplyCheck = {
36
32
  };
37
33
 
38
34
  /**
39
- * Inputs used to generate the first editable Book draft.
35
+ * Inputs used to generate the first editable Book.
40
36
  */
41
- export type GenerateManGoBookDraftInput = {
37
+ export type GenerateManGoBookInput = {
42
38
  readonly agentName: string;
43
39
  readonly agentBrief: string;
44
40
  };
45
41
 
46
- /**
47
- * Input used by the Book language conversion panel.
48
- */
49
- export type ConvertManGoDraftToBookInput = {
50
- readonly input: string;
51
- };
52
-
53
42
  /**
54
43
  * Input used by the step 4 live agent test.
55
44
  */
@@ -69,7 +58,7 @@ export type EvaluateManGoAgentReplyInput = {
69
58
  };
70
59
 
71
60
  /**
72
- * Fallback source used when step 4 is called before the draft exists.
61
+ * Fallback source used when step 4 is called before the Book exists.
73
62
  *
74
63
  * @private internal constant of manGo onboarding agent utilities
75
64
  */
@@ -121,24 +110,27 @@ function extractSingleBlockContent(response: string): string {
121
110
  }
122
111
 
123
112
  /**
124
- * Creates a prompt that asks the imported draft expert for a real Book-language draft.
113
+ * Creates a prompt that asks the imported Book expert for a complete Book-language source.
125
114
  *
126
115
  * @param input - Wizard name and brief.
127
- * @returns Prompt for the draft expert agent.
116
+ * @returns Prompt for the Book expert agent.
128
117
  *
129
118
  * @private internal utility of manGo onboarding agent utilities
130
119
  */
131
- function createBookDraftPrompt(input: GenerateManGoBookDraftInput): string {
120
+ function createBookPrompt(input: GenerateManGoBookInput): string {
132
121
  return spaceTrim(`
133
- Write an editable Promptbook Book-language draft for an AI agent.
122
+ Create a complete Promptbook Book-language source for one AI agent.
134
123
 
135
124
  Return only one \`book\` code block. Do not include any explanation outside the block.
125
+ This source is the final editable Book.
136
126
 
137
127
  Requirements:
138
128
  - Use the provided name as the agent title.
139
129
  - Write natural-language commitments in Czech unless the brief clearly asks for another language.
140
- - Include a useful PERSONA, GOAL, and practical RULE commitments derived from the brief.
130
+ - Include a useful PERSONA, GOAL, and practical RULE commitments derived from the description.
141
131
  - Keep commitment keywords in English.
132
+ - Use Book-language commitments such as WRITING SAMPLE, WRITING RULES, MESSAGE SUFFIX, and NOTE when they fit the agent.
133
+ - Do not use Markdown headings such as \`##\` as a substitute for Book-language commitments.
142
134
  - End the book with CLOSED.
143
135
 
144
136
  Name: ${input.agentName}
@@ -147,86 +139,42 @@ function createBookDraftPrompt(input: GenerateManGoBookDraftInput): string {
147
139
  }
148
140
 
149
141
  /**
150
- * Creates a first editable Book draft through the imported manGo onboarding AI agent.
142
+ * Creates the first editable Book through the imported manGo onboarding AI agent.
151
143
  *
152
144
  * @param input - Agent name and brief captured by the entry step.
153
145
  * @returns Editable Book source for the next wizard steps.
154
146
  */
155
- export async function generateManGoBookDraft(input: GenerateManGoBookDraftInput): Promise<string> {
147
+ export async function generateManGoBook(input: GenerateManGoBookInput): Promise<string> {
156
148
  const agentName = input.agentName.trim();
157
149
  const agentBrief = input.agentBrief.trim();
158
150
 
159
151
  if (!agentName || !agentBrief) {
160
152
  throw new NotAllowed(
161
153
  spaceTrim(`
162
- Cannot generate a manGo Book draft without both \`agentName\` and \`agentBrief\`.
154
+ Cannot generate a manGo Book without both \`agentName\` and \`agentBrief\`.
163
155
 
164
- Fill in the onboarding assignment before generating the draft.
156
+ Fill in the onboarding assignment before generating the Book.
165
157
  `),
166
158
  );
167
159
  }
168
160
 
169
161
  const response = await runManGoLiteAgent({
170
- bookSource: MAN_GO_DRAFT_EXPERT_BOOK,
171
- message: createBookDraftPrompt({ agentName, agentBrief }),
162
+ bookSource: MAN_GO_BOOK_EXPERT_BOOK,
163
+ message: createBookPrompt({ agentName, agentBrief }),
172
164
  });
173
165
  const book = extractSingleBlockContent(response);
174
166
 
175
167
  if (!book) {
176
168
  throw new PipelineExecutionError(
177
169
  spaceTrim(`
178
- The manGo draft expert returned an empty Book draft.
170
+ The manGo Book expert returned an empty Book.
179
171
 
180
- Try regenerating the draft from the onboarding step.
172
+ Try generating the Book again from the onboarding step.
181
173
  `),
182
174
  );
183
175
  }
184
176
 
185
- return book;
186
- }
187
-
188
- /**
189
- * Converts free-form draft text into canonical Book language through the imported book expert.
190
- *
191
- * @param input - Free-form editor content.
192
- * @returns Generated Book source and validation flag.
193
- */
194
- export async function convertManGoDraftToBook(
195
- input: ConvertManGoDraftToBookInput,
196
- ): Promise<{ readonly book: string; readonly isValid: boolean }> {
197
- const normalizedInput = input.input.trim();
198
-
199
- if (!normalizedInput) {
200
- throw new NotAllowed(
201
- spaceTrim(`
202
- Cannot convert an empty draft to Book language.
203
-
204
- Add draft content before running the manGo Book conversion.
205
- `),
206
- );
207
- }
208
-
209
- const response = await runManGoLiteAgent({
210
- bookSource: MAN_GO_BOOK_EXPERT_BOOK,
211
- message: spaceTrim(`
212
- Create a book that defines an agent with the following input:
213
-
214
- Wrap the output in a single \`book\` code block.
215
-
216
- Input:
217
- ${normalizedInput}
218
- `),
219
- });
220
- const book = extractSingleBlockContent(response);
221
-
222
- let isValid = true;
223
- try {
224
- validateBook(book);
225
- } catch {
226
- isValid = false;
227
- }
228
-
229
- return { book, isValid };
177
+ return validateBook(book);
230
178
  }
231
179
 
232
180
  /**
@@ -1,4 +1,5 @@
1
1
  import type { DnsRecordInstruction } from '../dnsRecords/DnsRecordInstruction';
2
+ import { buildStalwartMailServerHostname } from './stalwartMailBridge';
2
3
 
3
4
  /**
4
5
  * One DNS record required or recommended for reliable mail delivery.
@@ -15,18 +16,21 @@ export type EmailDnsInstruction = DnsRecordInstruction & {
15
16
  *
16
17
  * DKIM records are intentionally read from Stalwart's generated zone because their public keys must never be guessed.
17
18
  */
18
- export function createEmailDnsInstructions(domain: string): EmailDnsInstruction[] {
19
+ export function createEmailDnsInstructions(domain: string, publicIpAddress?: string | null): EmailDnsInstruction[] {
20
+ const mailServerHostname = buildStalwartMailServerHostname(domain);
21
+ const resolvedPublicIpAddress = publicIpAddress?.trim() || '<VPS_PUBLIC_IP>';
22
+
19
23
  return [
20
24
  {
21
25
  type: 'A',
22
- name: `mail.${domain}`,
23
- value: '<VPS_PUBLIC_IP>',
26
+ name: mailServerHostname,
27
+ value: resolvedPublicIpAddress,
24
28
  note: 'Mail server host. Use the same public IPv4 address as this VPS.',
25
29
  },
26
30
  {
27
31
  type: 'MX',
28
32
  name: domain,
29
- value: `10 mail.${domain}.`,
33
+ value: `10 ${mailServerHostname}.`,
30
34
  note: 'Routes inbound mail for the Agents Server domain to Stalwart.',
31
35
  },
32
36
  {
@@ -50,7 +54,7 @@ export function createEmailDnsInstructions(domain: string): EmailDnsInstruction[
50
54
  {
51
55
  type: 'A',
52
56
  name: `mta-sts.${domain}`,
53
- value: '<VPS_PUBLIC_IP>',
57
+ value: resolvedPublicIpAddress,
54
58
  note: 'Hosts the HTTPS MTA-STS policy for this mail domain.',
55
59
  },
56
60
  {