@promptbook/cli 0.113.0-4 → 0.113.0-8

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 (141) hide show
  1. package/apps/agents-server/src/app/admin/update/AdvancedOriginRepositoryPanel.tsx +76 -0
  2. package/apps/agents-server/src/app/admin/update/CurrentDeploymentCard.tsx +160 -0
  3. package/apps/agents-server/src/app/admin/update/PendingCommitsCard.tsx +86 -0
  4. package/apps/agents-server/src/app/admin/update/TargetEnvironmentCard.tsx +331 -0
  5. package/apps/agents-server/src/app/admin/update/UpdateClient.tsx +20 -873
  6. package/apps/agents-server/src/app/admin/update/UpdateJobCard.tsx +329 -0
  7. package/apps/agents-server/src/app/admin/update/UpdateOverview.ts +74 -0
  8. package/apps/agents-server/src/app/admin/update/buildDeploymentTimeBehindLabel.ts +29 -0
  9. package/apps/agents-server/src/app/admin/update/formatHumanReadableTimestamp.ts +18 -0
  10. package/apps/agents-server/src/app/admin/update/getUpdateJobFailureMessage.ts +13 -0
  11. package/apps/agents-server/src/app/admin/update/getUpdateJobSuccessMessage.ts +13 -0
  12. package/apps/agents-server/src/app/admin/update/useUpdateClientState.ts +441 -0
  13. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +13 -1
  14. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageClient.tsx +14 -559
  15. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageHeader.tsx +84 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/AgentCodePageSection.tsx +52 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/GeneratedCodePreview.tsx +138 -0
  18. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/GeneratedHarnessSection.tsx +98 -0
  19. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/SourceBookSection.tsx +66 -0
  20. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/TranspiledCodeErrorBanner.tsx +30 -0
  21. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/TranspiledCodeExportWarningBanner.tsx +62 -0
  22. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/Transpiler.ts +9 -0
  23. package/apps/agents-server/src/app/agents/[agentName]/export-as-transpiled-code/useAgentCodeExportState.ts +478 -0
  24. package/apps/agents-server/src/app/system/utilities/mocked-chats/cloneMockedChatPreset.ts +17 -0
  25. package/apps/agents-server/src/app/system/utilities/mocked-chats/confirmDeleteMockedChat.ts +16 -0
  26. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedMessage.ts +81 -0
  27. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedParticipant.ts +146 -0
  28. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDraftWithUpdatedSettings.ts +19 -0
  29. package/apps/agents-server/src/app/system/utilities/mocked-chats/createDuplicatedDraft.ts +66 -0
  30. package/apps/agents-server/src/app/system/utilities/mocked-chats/findMockedChatById.ts +51 -0
  31. package/apps/agents-server/src/app/system/utilities/mocked-chats/persistMockedChats.ts +51 -0
  32. package/apps/agents-server/src/app/system/utilities/mocked-chats/useMockedChatsEditorState.ts +16 -426
  33. package/apps/agents-server/src/components/Homepage/buildFreeGraphBoxLayout.ts +446 -0
  34. package/apps/agents-server/src/components/Homepage/buildGraphLayoutNodes.ts +415 -157
  35. package/apps/agents-server/src/components/Homepage/useAgentsGraphCanvasState.ts +2 -1
  36. package/apps/agents-server/src/database/sqlite/$provideLocalSqliteSupabase.ts +3 -1541
  37. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/LocalSqliteQueryBuilder.ts +623 -0
  38. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/LocalSqliteSupabaseClient.ts +64 -0
  39. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/ensureTable.ts +93 -0
  40. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteFilters.ts +202 -0
  41. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteMutationPayload.ts +131 -0
  42. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteRowOperations.ts +102 -0
  43. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteSql.ts +59 -0
  44. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteTableSchema.ts +329 -0
  45. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteTypes.ts +84 -0
  46. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/localSqliteValueCodec.ts +63 -0
  47. package/apps/agents-server/src/database/sqlite/localSqliteSupabase/normalizeSqliteError.ts +22 -0
  48. package/apps/agents-server/src/search/createDefaultServerSearchProviders/loadLocalOrganizationSearchDataset.ts +12 -1
  49. package/apps/agents-server/src/tools/send_email.ts +1 -2
  50. package/apps/agents-server/src/utils/agentOrganization/loadAgentOrganizationState.ts +13 -1
  51. package/apps/agents-server/src/utils/backup/createServerBackupZipStream.ts +7 -1382
  52. package/apps/agents-server/src/utils/backup/serverBackup/appendAgentBackupEntriesToZip.ts +27 -0
  53. package/apps/agents-server/src/utils/backup/serverBackup/appendConversationBackupEntriesToZip.ts +140 -0
  54. package/apps/agents-server/src/utils/backup/serverBackup/appendFileBackupEntriesToZip.ts +147 -0
  55. package/apps/agents-server/src/utils/backup/serverBackup/appendMessageBackupEntriesToZip.ts +65 -0
  56. package/apps/agents-server/src/utils/backup/serverBackup/appendMetadataBackupEntriesToZip.ts +39 -0
  57. package/apps/agents-server/src/utils/backup/serverBackup/appendSectionEntriesToZip.ts +92 -0
  58. package/apps/agents-server/src/utils/backup/serverBackup/appendUserBackupEntriesToZip.ts +80 -0
  59. package/apps/agents-server/src/utils/backup/serverBackup/createRedactedWalletBackupRecord.ts +34 -0
  60. package/apps/agents-server/src/utils/backup/serverBackup/createServerBackupManifest.ts +82 -0
  61. package/apps/agents-server/src/utils/backup/serverBackup/downloadBackupBinaryContent.ts +39 -0
  62. package/apps/agents-server/src/utils/backup/serverBackup/resolveFeedbackThreadMessages.ts +53 -0
  63. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupAttachments.ts +151 -0
  64. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupContext.ts +167 -0
  65. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupFilenames.ts +161 -0
  66. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupPreviews.ts +97 -0
  67. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupRowUtilities.ts +158 -0
  68. package/apps/agents-server/src/utils/backup/serverBackup/serverBackupTypes.ts +59 -0
  69. package/apps/agents-server/src/utils/createLocalAgentSourceImporter.ts +159 -0
  70. package/apps/agents-server/src/utils/createMissingImportedAgentFallback.ts +60 -0
  71. package/apps/agents-server/src/utils/customDomainRouting.ts +157 -12
  72. package/apps/agents-server/src/utils/externalChatRunner/processExternalUserChatJob.ts +1 -1
  73. package/apps/agents-server/src/utils/importAgentWithFallback.ts +1 -58
  74. package/apps/agents-server/src/utils/localAgentRouteReferences.ts +167 -0
  75. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +1 -1
  76. package/apps/agents-server/src/utils/managementApi/managementApiAgents.ts +17 -3
  77. package/apps/agents-server/src/utils/messages/sendMessage.ts +5 -3
  78. package/apps/agents-server/src/utils/resolveAgentStateFromSource.ts +7 -1
  79. package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +54 -5
  80. package/apps/agents-server/src/utils/resolveServerAgentContext.ts +12 -1
  81. package/apps/agents-server/src/utils/resolveStoredAgentState.ts +2 -1
  82. package/apps/agents-server/src/utils/speech-to-text/SpeechToTextFailoverRecognition/SpeechToTextFailoverRecognitionProviderRuntime.ts +0 -1
  83. package/apps/agents-server/src/utils/speech-to-text/SpeechToTextFailoverRecognition.ts +34 -2
  84. package/apps/agents-server/src/utils/userChat/userChatMessageLifecycle.ts +39 -9
  85. package/apps/agents-server/tests/e2e/support/ChatHistoryNavigationSupport.ts +5 -0
  86. package/esm/index.es.js +875 -60
  87. package/esm/index.es.js.map +1 -1
  88. package/esm/scripts/find-refactor-candidates/find-refactor-candidates.d.ts +7 -0
  89. package/esm/scripts/find-refactor-candidates/selectMostImportantRefactorCandidates.d.ts +12 -0
  90. package/esm/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +20 -0
  91. package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +5 -0
  92. package/esm/scripts/run-codex-prompts/ui/buildCoderRunAgentVisual.d.ts +29 -0
  93. package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +4 -0
  94. package/esm/src/avatars/renderAvatarVisualAsciiArt.d.ts +75 -0
  95. package/esm/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
  96. package/esm/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
  97. package/esm/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
  98. package/esm/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -0
  99. package/esm/src/cli/cli-commands/common/createPositiveIntegerOptionParser.d.ts +10 -0
  100. package/esm/src/utils/ascii-art/$detectTerminalAnsiColorDepth.d.ts +15 -0
  101. package/esm/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +80 -0
  102. package/esm/src/version.d.ts +1 -1
  103. package/package.json +1 -1
  104. package/src/avatars/avatarAnimationScheduler.ts +2 -1
  105. package/src/avatars/renderAvatarVisualAsciiArt.ts +138 -0
  106. package/src/avatars/visuals/octopus3d3AvatarVisual.ts +6 -2
  107. package/src/avatars/visuals/octopus3d4AvatarVisual.ts +14 -18
  108. package/src/book-components/Chat/Chat/insertDictationChunk.ts +3 -3
  109. package/src/book-components/Chat/Chat/learnDictationDictionary.ts +1 -1
  110. package/src/book-components/Chat/Chat/useChatInputAreaDictation.ts +133 -26
  111. package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +3 -1
  112. package/src/cli/cli-commands/coder/boilerplateTemplates.ts +14 -21
  113. package/src/cli/cli-commands/coder/find-refactor-candidates.ts +9 -2
  114. package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +1 -4
  115. package/src/cli/cli-commands/coder/run.ts +3 -27
  116. package/src/cli/cli-commands/common/createPositiveIntegerOptionParser.ts +31 -0
  117. package/src/commitments/TEAM/TEAM.ts +5 -5
  118. package/src/other/templates/getTemplatesPipelineCollection.ts +770 -1169
  119. package/src/utils/ascii-art/$detectTerminalAnsiColorDepth.ts +45 -0
  120. package/src/utils/ascii-art/convertImageDataToAsciiArt.ts +396 -0
  121. package/src/version.ts +2 -2
  122. package/src/versions.txt +2 -0
  123. package/umd/index.umd.js +875 -60
  124. package/umd/index.umd.js.map +1 -1
  125. package/umd/scripts/find-refactor-candidates/find-refactor-candidates.d.ts +7 -0
  126. package/umd/scripts/find-refactor-candidates/selectMostImportantRefactorCandidates.d.ts +12 -0
  127. package/umd/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +20 -0
  128. package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +5 -0
  129. package/umd/scripts/run-codex-prompts/ui/buildCoderRunAgentVisual.d.ts +29 -0
  130. package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +4 -0
  131. package/umd/src/avatars/renderAvatarVisualAsciiArt.d.ts +75 -0
  132. package/umd/src/book-components/Chat/Chat/insertDictationChunk.d.ts +1 -1
  133. package/umd/src/book-components/Chat/Chat/insertDictationChunk.test.d.ts +1 -0
  134. package/umd/src/book-components/Chat/Chat/learnDictationDictionary.test.d.ts +1 -0
  135. package/umd/src/book-components/Chat/Chat/refineFinalDictationChunk.test.d.ts +1 -0
  136. package/umd/src/cli/cli-commands/common/createPositiveIntegerOptionParser.d.ts +10 -0
  137. package/umd/src/utils/ascii-art/$detectTerminalAnsiColorDepth.d.ts +15 -0
  138. package/umd/src/utils/ascii-art/convertImageDataToAsciiArt.d.ts +80 -0
  139. package/umd/src/version.d.ts +1 -1
  140. package/esm/scripts/run-codex-prompts/common/resolveAgentSystemMessage.d.ts +0 -6
  141. package/umd/scripts/run-codex-prompts/common/resolveAgentSystemMessage.d.ts +0 -6
@@ -0,0 +1,45 @@
1
+ import type { AsciiArtColorDepth } from './convertImageDataToAsciiArt';
2
+
3
+ /**
4
+ * Detects the ANSI color depth supported by the current terminal.
5
+ *
6
+ * Prefers 24-bit true color when the environment advertises it (modern terminals such as
7
+ * Windows Terminal, ConEmu, VS Code, mintty, iTerm2, and WezTerm) and falls back to the
8
+ * portable 256-color palette otherwise.
9
+ *
10
+ * Note: `$` is used to indicate that this function is not a pure function - it reads the process environment
11
+ *
12
+ * @returns Color depth usable by `convertImageDataToAsciiArt`
13
+ *
14
+ * @private within the repository
15
+ */
16
+ export function $detectTerminalAnsiColorDepth(): AsciiArtColorDepth {
17
+ if (typeof process === 'undefined' || !process.env) {
18
+ return 'ANSI_256';
19
+ }
20
+
21
+ const colorTerm = (process.env.COLORTERM || '').toLowerCase();
22
+ if (colorTerm.includes('truecolor') || colorTerm.includes('24bit')) {
23
+ return 'TRUE_COLOR';
24
+ }
25
+
26
+ if (process.env.WT_SESSION !== undefined) {
27
+ return 'TRUE_COLOR'; // <- Note: Windows Terminal always supports true color but does not set COLORTERM
28
+ }
29
+
30
+ if (process.env.ConEmuANSI === 'ON') {
31
+ return 'TRUE_COLOR';
32
+ }
33
+
34
+ const termProgram = process.env.TERM_PROGRAM || '';
35
+ if (['vscode', 'iTerm.app', 'WezTerm', 'ghostty', 'Hyper'].includes(termProgram)) {
36
+ return 'TRUE_COLOR';
37
+ }
38
+
39
+ const term = (process.env.TERM || '').toLowerCase();
40
+ if (term.includes('truecolor') || term.includes('24bit') || term.includes('direct')) {
41
+ return 'TRUE_COLOR';
42
+ }
43
+
44
+ return 'ANSI_256';
45
+ }
@@ -0,0 +1,396 @@
1
+ import { spaceTrim } from 'spacetrim';
2
+ import { UnexpectedError } from '../../errors/UnexpectedError';
3
+
4
+ /**
5
+ * Color depth of the ANSI escape codes emitted by the ASCII-art conversion.
6
+ *
7
+ * - `TRUE_COLOR` emits 24-bit `38;2;r;g;b` / `48;2;r;g;b` sequences
8
+ * - `ANSI_256` approximates colors on the 256-color ANSI cube for older terminals
9
+ *
10
+ * @private within the repository
11
+ */
12
+ export type AsciiArtColorDepth = 'TRUE_COLOR' | 'ANSI_256';
13
+
14
+ /**
15
+ * Minimal structural subset of the DOM `ImageData` accepted by the ASCII-art conversion.
16
+ *
17
+ * Works with browser canvas `ImageData`, `@napi-rs/canvas` image data, or any raw RGBA buffer.
18
+ *
19
+ * @private within the repository
20
+ */
21
+ export type AsciiArtImageData = {
22
+ /**
23
+ * Source image width in pixels.
24
+ */
25
+ readonly width: number;
26
+
27
+ /**
28
+ * Source image height in pixels.
29
+ */
30
+ readonly height: number;
31
+
32
+ /**
33
+ * Flat RGBA pixel buffer with 4 bytes per pixel.
34
+ */
35
+ readonly data: ArrayLike<number>;
36
+ };
37
+
38
+ /**
39
+ * Options for `convertImageDataToAsciiArt`.
40
+ *
41
+ * @private within the repository
42
+ */
43
+ export type ConvertImageDataToAsciiArtOptions = {
44
+ /**
45
+ * Source pixels to convert.
46
+ */
47
+ readonly imageData: AsciiArtImageData;
48
+
49
+ /**
50
+ * Output width in terminal character cells.
51
+ */
52
+ readonly columns: number;
53
+
54
+ /**
55
+ * Output height in terminal character cells.
56
+ *
57
+ * Each character cell renders two vertically stacked pixels, so `rows = columns / 2`
58
+ * keeps a square image visually square in a common terminal font.
59
+ */
60
+ readonly rows: number;
61
+
62
+ /**
63
+ * Color depth of the emitted ANSI escape codes.
64
+ *
65
+ * @default 'TRUE_COLOR'
66
+ */
67
+ readonly colorDepth?: AsciiArtColorDepth;
68
+
69
+ /**
70
+ * Alpha channel value (0-255) below which an averaged half-cell is treated as fully transparent.
71
+ *
72
+ * @default 32
73
+ */
74
+ readonly alphaThreshold?: number;
75
+ };
76
+
77
+ /**
78
+ * Default alpha channel value below which a half-cell is rendered as terminal background.
79
+ *
80
+ * @private within the repository
81
+ */
82
+ const DEFAULT_ALPHA_THRESHOLD = 32;
83
+
84
+ /**
85
+ * Number of channels per pixel in an RGBA buffer.
86
+ *
87
+ * @private within the repository
88
+ */
89
+ const RGBA_CHANNEL_COUNT = 4;
90
+
91
+ /**
92
+ * Upper half block character - foreground paints the top pixel, background paints the bottom pixel.
93
+ *
94
+ * @private within the repository
95
+ */
96
+ const UPPER_HALF_BLOCK = '▀'; // <- ▀
97
+
98
+ /**
99
+ * Lower half block character - foreground paints the bottom pixel while the top pixel stays transparent.
100
+ *
101
+ * @private within the repository
102
+ */
103
+ const LOWER_HALF_BLOCK = '▄'; // <- ▄
104
+
105
+ /**
106
+ * ANSI escape sequence that resets all colors and attributes.
107
+ *
108
+ * @private within the repository
109
+ */
110
+ const ANSI_RESET = '\u001b[0m';
111
+
112
+ /**
113
+ * Maximum spread between RGB channels for a color to be treated as (nearly) achromatic gray.
114
+ *
115
+ * @private within the repository
116
+ */
117
+ const ANSI_256_ACHROMATIC_CHANNEL_SPREAD = 12;
118
+
119
+ /**
120
+ * Gray level above which an achromatic color maps to the pure white color-cube entry.
121
+ *
122
+ * @private within the repository
123
+ */
124
+ const ANSI_256_NEAR_WHITE_GRAY_LEVEL = 246;
125
+
126
+ /**
127
+ * Index of pure white inside the 6×6×6 ANSI color cube.
128
+ *
129
+ * @private within the repository
130
+ */
131
+ const ANSI_256_WHITE_INDEX = 231;
132
+
133
+ /**
134
+ * Brightness of the lightest entry of the ANSI 256 grayscale ramp.
135
+ *
136
+ * @private within the repository
137
+ */
138
+ const ANSI_256_GRAYSCALE_RAMP_MAX_LEVEL = 238;
139
+
140
+ /**
141
+ * Number of grayscale ramp steps above its first entry (ANSI indexes 232-255).
142
+ *
143
+ * @private within the repository
144
+ */
145
+ const ANSI_256_GRAYSCALE_RAMP_INDEX_SPAN = 23;
146
+
147
+ /**
148
+ * Area-averaged color of one half of a character cell.
149
+ *
150
+ * @private helper of `convertImageDataToAsciiArt`
151
+ */
152
+ type HalfCellColor = {
153
+ readonly red: number;
154
+ readonly green: number;
155
+ readonly blue: number;
156
+ readonly isOpaque: boolean;
157
+ };
158
+
159
+ /**
160
+ * Converts raw RGBA image pixels into colored ASCII art for ANSI terminals.
161
+ *
162
+ * This is the universal image-to-terminal technique used across the repository:
163
+ * every output character cell covers a rectangular region of source pixels which is
164
+ * split into a top and bottom half; each half is area-averaged and rendered with
165
+ * half-block characters (`▀` / `▄`) so one character shows two "pixels" vertically.
166
+ * Transparent halves keep the terminal background so non-rectangular images
167
+ * (for example rounded avatar cards) compose naturally into any terminal UI.
168
+ *
169
+ * @param options Source pixels, output grid size, and ANSI color depth.
170
+ * @returns One ANSI-colored string per output row, each ending with a color reset.
171
+ *
172
+ * @private within the repository
173
+ */
174
+ export function convertImageDataToAsciiArt(options: ConvertImageDataToAsciiArtOptions): ReadonlyArray<string> {
175
+ const { imageData, columns, rows, colorDepth = 'TRUE_COLOR', alphaThreshold = DEFAULT_ALPHA_THRESHOLD } = options;
176
+
177
+ if (!Number.isInteger(columns) || columns <= 0 || !Number.isInteger(rows) || rows <= 0) {
178
+ throw new UnexpectedError(
179
+ spaceTrim(`
180
+ ASCII-art grid size is invalid.
181
+
182
+ Both \`columns\` and \`rows\` must be positive integers but \`${columns}\` × \`${rows}\` was requested.
183
+ `),
184
+ );
185
+ }
186
+
187
+ if (
188
+ imageData.width <= 0 ||
189
+ imageData.height <= 0 ||
190
+ imageData.data.length < imageData.width * imageData.height * RGBA_CHANNEL_COUNT
191
+ ) {
192
+ throw new UnexpectedError(
193
+ spaceTrim(`
194
+ ASCII-art source image data is invalid.
195
+
196
+ Expected a RGBA buffer of at least \`${imageData.width} × ${imageData.height} × ${RGBA_CHANNEL_COUNT}\` bytes
197
+ but got \`${imageData.data.length}\` bytes.
198
+ `),
199
+ );
200
+ }
201
+
202
+ const halfCellRowCount = rows * 2;
203
+ const asciiArtLines: Array<string> = [];
204
+
205
+ for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
206
+ let line = '';
207
+ let currentForegroundCode: string | undefined = undefined;
208
+ let currentBackgroundCode: string | undefined = undefined;
209
+
210
+ for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
211
+ const topHalfColor = computeHalfCellColor(
212
+ imageData,
213
+ columnIndex,
214
+ rowIndex * 2,
215
+ columns,
216
+ halfCellRowCount,
217
+ alphaThreshold,
218
+ );
219
+ const bottomHalfColor = computeHalfCellColor(
220
+ imageData,
221
+ columnIndex,
222
+ rowIndex * 2 + 1,
223
+ columns,
224
+ halfCellRowCount,
225
+ alphaThreshold,
226
+ );
227
+
228
+ let character: string;
229
+ let nextForegroundCode: string | undefined;
230
+ let nextBackgroundCode: string | undefined;
231
+
232
+ if (topHalfColor.isOpaque && bottomHalfColor.isOpaque) {
233
+ character = UPPER_HALF_BLOCK;
234
+ nextForegroundCode = createForegroundColorCode(topHalfColor, colorDepth);
235
+ nextBackgroundCode = createBackgroundColorCode(bottomHalfColor, colorDepth);
236
+ } else if (topHalfColor.isOpaque) {
237
+ character = UPPER_HALF_BLOCK;
238
+ nextForegroundCode = createForegroundColorCode(topHalfColor, colorDepth);
239
+ nextBackgroundCode = undefined;
240
+ } else if (bottomHalfColor.isOpaque) {
241
+ character = LOWER_HALF_BLOCK;
242
+ nextForegroundCode = createForegroundColorCode(bottomHalfColor, colorDepth);
243
+ nextBackgroundCode = undefined;
244
+ } else {
245
+ character = ' ';
246
+ nextForegroundCode = undefined;
247
+ nextBackgroundCode = undefined;
248
+ }
249
+
250
+ if (nextForegroundCode !== currentForegroundCode || nextBackgroundCode !== currentBackgroundCode) {
251
+ // Note: A reset is required whenever a previously set color must be cleared,
252
+ // otherwise stale background color would bleed into transparent cells.
253
+ const isResetNeeded =
254
+ (currentForegroundCode !== undefined && nextForegroundCode === undefined) ||
255
+ (currentBackgroundCode !== undefined && nextBackgroundCode === undefined);
256
+
257
+ if (isResetNeeded) {
258
+ line += ANSI_RESET;
259
+ currentForegroundCode = undefined;
260
+ currentBackgroundCode = undefined;
261
+ }
262
+
263
+ if (nextForegroundCode !== undefined && nextForegroundCode !== currentForegroundCode) {
264
+ line += nextForegroundCode;
265
+ }
266
+
267
+ if (nextBackgroundCode !== undefined && nextBackgroundCode !== currentBackgroundCode) {
268
+ line += nextBackgroundCode;
269
+ }
270
+
271
+ currentForegroundCode = nextForegroundCode;
272
+ currentBackgroundCode = nextBackgroundCode;
273
+ }
274
+
275
+ line += character;
276
+ }
277
+
278
+ if (currentForegroundCode !== undefined || currentBackgroundCode !== undefined) {
279
+ line += ANSI_RESET;
280
+ }
281
+
282
+ asciiArtLines.push(line);
283
+ }
284
+
285
+ return asciiArtLines;
286
+ }
287
+
288
+ /**
289
+ * Computes the area-averaged color of one half-cell of the output grid.
290
+ *
291
+ * Color channels are alpha-weighted so semi-transparent edge pixels do not darken towards black.
292
+ *
293
+ * @private helper of `convertImageDataToAsciiArt`
294
+ */
295
+ function computeHalfCellColor(
296
+ imageData: AsciiArtImageData,
297
+ columnIndex: number,
298
+ halfCellRowIndex: number,
299
+ columns: number,
300
+ halfCellRowCount: number,
301
+ alphaThreshold: number,
302
+ ): HalfCellColor {
303
+ const startX = Math.floor((columnIndex * imageData.width) / columns);
304
+ const endX = Math.max(startX + 1, Math.floor(((columnIndex + 1) * imageData.width) / columns));
305
+ const startY = Math.floor((halfCellRowIndex * imageData.height) / halfCellRowCount);
306
+ const endY = Math.max(startY + 1, Math.floor(((halfCellRowIndex + 1) * imageData.height) / halfCellRowCount));
307
+
308
+ let redSum = 0;
309
+ let greenSum = 0;
310
+ let blueSum = 0;
311
+ let alphaSum = 0;
312
+ let sampledPixelCount = 0;
313
+
314
+ for (let y = startY; y < endY && y < imageData.height; y++) {
315
+ for (let x = startX; x < endX && x < imageData.width; x++) {
316
+ const pixelOffset = (y * imageData.width + x) * RGBA_CHANNEL_COUNT;
317
+ const alpha = imageData.data[pixelOffset + 3]!;
318
+
319
+ redSum += imageData.data[pixelOffset]! * alpha;
320
+ greenSum += imageData.data[pixelOffset + 1]! * alpha;
321
+ blueSum += imageData.data[pixelOffset + 2]! * alpha;
322
+ alphaSum += alpha;
323
+ sampledPixelCount++;
324
+ }
325
+ }
326
+
327
+ const averageAlpha = sampledPixelCount === 0 ? 0 : alphaSum / sampledPixelCount;
328
+
329
+ if (averageAlpha < alphaThreshold || alphaSum === 0) {
330
+ return { red: 0, green: 0, blue: 0, isOpaque: false };
331
+ }
332
+
333
+ return {
334
+ red: Math.round(redSum / alphaSum),
335
+ green: Math.round(greenSum / alphaSum),
336
+ blue: Math.round(blueSum / alphaSum),
337
+ isOpaque: true,
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Creates the ANSI escape code that sets the foreground color of following characters.
343
+ *
344
+ * @private helper of `convertImageDataToAsciiArt`
345
+ */
346
+ function createForegroundColorCode(color: HalfCellColor, colorDepth: AsciiArtColorDepth): string {
347
+ if (colorDepth === 'TRUE_COLOR') {
348
+ return `\u001b[38;2;${color.red};${color.green};${color.blue}m`;
349
+ }
350
+
351
+ return `\u001b[38;5;${mapColorToAnsi256(color)}m`;
352
+ }
353
+
354
+ /**
355
+ * Creates the ANSI escape code that sets the background color of following characters.
356
+ *
357
+ * @private helper of `convertImageDataToAsciiArt`
358
+ */
359
+ function createBackgroundColorCode(color: HalfCellColor, colorDepth: AsciiArtColorDepth): string {
360
+ if (colorDepth === 'TRUE_COLOR') {
361
+ return `\u001b[48;2;${color.red};${color.green};${color.blue}m`;
362
+ }
363
+
364
+ return `\u001b[48;5;${mapColorToAnsi256(color)}m`;
365
+ }
366
+
367
+ /**
368
+ * Maps a 24-bit color onto the closest entry of the 256-color ANSI palette.
369
+ *
370
+ * Uses the 6×6×6 color cube (entries 16-231) and the grayscale ramp (entries 232-255).
371
+ *
372
+ * @private helper of `convertImageDataToAsciiArt`
373
+ */
374
+ function mapColorToAnsi256(color: HalfCellColor): number {
375
+ const { red, green, blue } = color;
376
+
377
+ // Note: Prefer the finer grayscale ramp when the color is (nearly) achromatic
378
+ const maxChannel = Math.max(red, green, blue);
379
+ const minChannel = Math.min(red, green, blue);
380
+ if (maxChannel - minChannel < ANSI_256_ACHROMATIC_CHANNEL_SPREAD) {
381
+ const gray = Math.round((red + green + blue) / 3);
382
+ if (gray < 4) {
383
+ return 16; // <- Note: Pure black lives in the color cube
384
+ }
385
+ if (gray > ANSI_256_NEAR_WHITE_GRAY_LEVEL) {
386
+ return ANSI_256_WHITE_INDEX; // <- Note: Pure white lives in the color cube
387
+ }
388
+ return 232 + Math.round(((gray - 8) / ANSI_256_GRAYSCALE_RAMP_MAX_LEVEL) * ANSI_256_GRAYSCALE_RAMP_INDEX_SPAN);
389
+ }
390
+
391
+ const redIndex = Math.round((red / 255) * 5);
392
+ const greenIndex = Math.round((green / 255) * 5);
393
+ const blueIndex = Math.round((blue / 255) * 5);
394
+
395
+ return 16 + 36 * redIndex + 6 * greenIndex + blueIndex;
396
+ }
package/src/version.ts CHANGED
@@ -16,11 +16,11 @@ export const BOOK_LANGUAGE_VERSION: string_semantic_version = '2.0.0';
16
16
  * @generated
17
17
  * @see https://github.com/webgptorg/promptbook
18
18
  */
19
- export const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version = '0.113.0-4';
19
+ export const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version = '0.113.0-8';
20
20
 
21
21
  /**
22
22
  * Represents the version string of the Promptbook engine.
23
- * It follows semantic versioning (e.g., `0.113.0-3`).
23
+ * It follows semantic versioning (e.g., `0.113.0-5`).
24
24
  *
25
25
  * @generated
26
26
  */
package/src/versions.txt CHANGED
@@ -1170,3 +1170,5 @@
1170
1170
  0.113.0-1
1171
1171
  0.113.0-3
1172
1172
  0.113.0-4
1173
+ 0.113.0-5
1174
+ 0.113.0-8