@promptbook/cli 0.112.0-65 → 0.112.0-66
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.
- package/esm/index.es.js +1233 -298
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/ui/buildAgentRunInitialsVisual.d.ts +4 -0
- package/esm/scripts/run-agent-messages/ui/buildAgentRunUiFrame.d.ts +5 -0
- package/esm/scripts/run-agent-messages/ui/loadAgentRunUiMetadata.d.ts +16 -0
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +6 -0
- package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
- package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +49 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +4 -1
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/esm/src/avatars/visuals/minecraft2AvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/minecraftAvatarVisualShared.d.ts +48 -0
- package/esm/src/cli/cli-commands/coder/ensureCoderGitignoreFile.d.ts +1 -1
- package/esm/src/config.d.ts +3 -3
- package/esm/src/utils/files/getPromptbookTempPath.d.ts +24 -0
- package/esm/src/utils/files/getPromptbookTempPath.test.d.ts +1 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +1232 -297
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/ui/buildAgentRunInitialsVisual.d.ts +4 -0
- package/umd/scripts/run-agent-messages/ui/buildAgentRunUiFrame.d.ts +5 -0
- package/umd/scripts/run-agent-messages/ui/loadAgentRunUiMetadata.d.ts +16 -0
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +6 -0
- package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +1 -0
- package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +49 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +4 -1
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +1 -1
- package/umd/src/avatars/visuals/minecraft2AvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/minecraftAvatarVisualShared.d.ts +48 -0
- package/umd/src/cli/cli-commands/coder/ensureCoderGitignoreFile.d.ts +1 -1
- package/umd/src/config.d.ts +3 -3
- package/umd/src/utils/files/getPromptbookTempPath.d.ts +24 -0
- package/umd/src/utils/files/getPromptbookTempPath.test.d.ts +1 -0
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -2,7 +2,7 @@ import colors from 'colors';
|
|
|
2
2
|
import commander, { Option } from 'commander';
|
|
3
3
|
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
4
4
|
import { writeFile, stat, mkdir, readFile, access, constants, readdir, watch, unlink, rm, rename, rmdir, appendFile } from 'fs/promises';
|
|
5
|
-
import { join, basename, dirname, isAbsolute, relative, resolve, extname } from 'path';
|
|
5
|
+
import { posix, join, basename, dirname, isAbsolute, relative, resolve, extname } from 'path';
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import { mkdirSync, writeFileSync, statSync, readFileSync, existsSync } from 'fs';
|
|
8
8
|
import { forTime, forEver } from 'waitasecond';
|
|
@@ -57,7 +57,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
57
57
|
* @generated
|
|
58
58
|
* @see https://github.com/webgptorg/promptbook
|
|
59
59
|
*/
|
|
60
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
60
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-66';
|
|
61
61
|
/**
|
|
62
62
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
63
63
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -990,6 +990,45 @@ function saturate(amount) {
|
|
|
990
990
|
}
|
|
991
991
|
// TODO: Maybe implement by mix+hsl
|
|
992
992
|
|
|
993
|
+
/**
|
|
994
|
+
* Relative directory name without the `./` prefix for Git ignore rules and glob patterns.
|
|
995
|
+
*
|
|
996
|
+
* @private internal utility for Promptbook-owned temp files
|
|
997
|
+
*/
|
|
998
|
+
const PROMPTBOOK_TEMP_DIRECTORY_NAME = '.promptbook';
|
|
999
|
+
/**
|
|
1000
|
+
* Builds one project-relative path inside the shared Promptbook working directory.
|
|
1001
|
+
*
|
|
1002
|
+
* @private internal utility for Promptbook-owned temp files
|
|
1003
|
+
*/
|
|
1004
|
+
function getPromptbookTempPath(...pathSegments) {
|
|
1005
|
+
return `./${getPromptbookTempPosixPath(...pathSegments)}`;
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* Builds one absolute filesystem path inside the shared Promptbook working directory for a project root.
|
|
1009
|
+
*
|
|
1010
|
+
* @private internal utility for Promptbook-owned temp files
|
|
1011
|
+
*/
|
|
1012
|
+
function resolvePromptbookTempPath(projectPath, ...pathSegments) {
|
|
1013
|
+
return join(projectPath, PROMPTBOOK_TEMP_DIRECTORY_NAME, ...pathSegments);
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* Builds one POSIX path fragment inside the shared Promptbook working directory for globs and generated text files.
|
|
1017
|
+
*
|
|
1018
|
+
* @private internal utility for Promptbook-owned temp files
|
|
1019
|
+
*/
|
|
1020
|
+
function getPromptbookTempPosixPath(...pathSegments) {
|
|
1021
|
+
return posix.join(PROMPTBOOK_TEMP_DIRECTORY_NAME, ...pathSegments);
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Builds one rooted `.gitignore` rule targeting a path inside the shared Promptbook working directory.
|
|
1025
|
+
*
|
|
1026
|
+
* @private internal utility for Promptbook-owned temp files
|
|
1027
|
+
*/
|
|
1028
|
+
function getPromptbookTempGitignoreRule(...pathSegments) {
|
|
1029
|
+
return `/${getPromptbookTempPosixPath(...pathSegments)}`;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
993
1032
|
/**
|
|
994
1033
|
* Returns the same value that is passed as argument.
|
|
995
1034
|
* No side effects.
|
|
@@ -1232,7 +1271,6 @@ const DEFAULT_BOOKS_DIRNAME = './books';
|
|
|
1232
1271
|
*/
|
|
1233
1272
|
const DEFAULT_AGENTS_DIRNAME = './agents';
|
|
1234
1273
|
// <- TODO: [🕝] Make also `AGENTS_DIRNAME_ALTERNATIVES`
|
|
1235
|
-
// TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
|
|
1236
1274
|
/**
|
|
1237
1275
|
* Where to store the temporary downloads
|
|
1238
1276
|
*
|
|
@@ -1240,7 +1278,7 @@ const DEFAULT_AGENTS_DIRNAME = './agents';
|
|
|
1240
1278
|
*
|
|
1241
1279
|
* @public exported from `@promptbook/core`
|
|
1242
1280
|
*/
|
|
1243
|
-
const DEFAULT_DOWNLOAD_CACHE_DIRNAME = '
|
|
1281
|
+
const DEFAULT_DOWNLOAD_CACHE_DIRNAME = getPromptbookTempPath('download-cache');
|
|
1244
1282
|
/**
|
|
1245
1283
|
* Where to store the cache of executions for promptbook CLI
|
|
1246
1284
|
*
|
|
@@ -1248,7 +1286,7 @@ const DEFAULT_DOWNLOAD_CACHE_DIRNAME = './.promptbook/download-cache';
|
|
|
1248
1286
|
*
|
|
1249
1287
|
* @public exported from `@promptbook/core`
|
|
1250
1288
|
*/
|
|
1251
|
-
const DEFAULT_EXECUTION_CACHE_DIRNAME = '
|
|
1289
|
+
const DEFAULT_EXECUTION_CACHE_DIRNAME = getPromptbookTempPath('execution-cache');
|
|
1252
1290
|
/**
|
|
1253
1291
|
* Where to store the scrape cache
|
|
1254
1292
|
*
|
|
@@ -1256,7 +1294,7 @@ const DEFAULT_EXECUTION_CACHE_DIRNAME = './.promptbook/execution-cache';
|
|
|
1256
1294
|
*
|
|
1257
1295
|
* @public exported from `@promptbook/core`
|
|
1258
1296
|
*/
|
|
1259
|
-
const DEFAULT_SCRAPE_CACHE_DIRNAME = '
|
|
1297
|
+
const DEFAULT_SCRAPE_CACHE_DIRNAME = getPromptbookTempPath('scrape-cache');
|
|
1260
1298
|
/**
|
|
1261
1299
|
* Id of application for the CLI when using remote server
|
|
1262
1300
|
*
|
|
@@ -2175,9 +2213,8 @@ const SOURCE_FILE_IGNORE_GLOBS = [
|
|
|
2175
2213
|
'**/.git/**',
|
|
2176
2214
|
'**/.idea/**',
|
|
2177
2215
|
'**/.vscode/**',
|
|
2178
|
-
|
|
2216
|
+
`**/${getPromptbookTempPosixPath()}/**`,
|
|
2179
2217
|
'**/.next/**',
|
|
2180
|
-
'**/.tmp/**',
|
|
2181
2218
|
'**/tmp/**',
|
|
2182
2219
|
'**/coverage/**',
|
|
2183
2220
|
'**/dist/**',
|
|
@@ -2997,13 +3034,9 @@ function escapeRegExp$1(value) {
|
|
|
2997
3034
|
*/
|
|
2998
3035
|
const GITIGNORE_FILE_PATH = '.gitignore';
|
|
2999
3036
|
/**
|
|
3000
|
-
* Promptbook
|
|
3037
|
+
* Shared Promptbook working directory that should stay out of version control.
|
|
3001
3038
|
*/
|
|
3002
|
-
const CODER_TEMP_GITIGNORE_RULE =
|
|
3003
|
-
/**
|
|
3004
|
-
* Promptbook coder cache directory that should stay out of version control.
|
|
3005
|
-
*/
|
|
3006
|
-
const CODER_CACHE_GITIGNORE_RULE = '/.promptbook/ptbk-coder';
|
|
3039
|
+
const CODER_TEMP_GITIGNORE_RULE = getPromptbookTempGitignoreRule();
|
|
3007
3040
|
/**
|
|
3008
3041
|
* Promptbook coder environment file that should stay out of version control.
|
|
3009
3042
|
*/
|
|
@@ -3013,7 +3046,7 @@ const CODER_ENV_GITIGNORE_RULE = '.env';
|
|
|
3013
3046
|
*/
|
|
3014
3047
|
const CODER_GITIGNORE_HEADER = '# Promptbook Coder';
|
|
3015
3048
|
/**
|
|
3016
|
-
* Ensures `.gitignore` contains the
|
|
3049
|
+
* Ensures `.gitignore` contains the shared Promptbook working-directory entry.
|
|
3017
3050
|
*
|
|
3018
3051
|
* @private function of `initializeCoderProjectConfiguration`
|
|
3019
3052
|
*/
|
|
@@ -3032,7 +3065,7 @@ async function ensureCoderGitignoreFile(projectPath) {
|
|
|
3032
3065
|
* Returns the Promptbook coder gitignore rules that still need to be added.
|
|
3033
3066
|
*/
|
|
3034
3067
|
function getMissingCoderGitignoreRules(gitignoreContent) {
|
|
3035
|
-
const requiredRules = [CODER_TEMP_GITIGNORE_RULE,
|
|
3068
|
+
const requiredRules = [CODER_TEMP_GITIGNORE_RULE, CODER_ENV_GITIGNORE_RULE];
|
|
3036
3069
|
return requiredRules.filter((rule) => !hasGitignoreRule(gitignoreContent, rule));
|
|
3037
3070
|
}
|
|
3038
3071
|
/**
|
|
@@ -22688,6 +22721,177 @@ function drawFractalCore(context, size, palette, timeMs, corePhase) {
|
|
|
22688
22721
|
context.restore();
|
|
22689
22722
|
}
|
|
22690
22723
|
|
|
22724
|
+
/* eslint-disable no-magic-numbers */
|
|
22725
|
+
/**
|
|
22726
|
+
* Builds the seeded six-face texture pack used by the Minecraft-style head cuboid.
|
|
22727
|
+
*
|
|
22728
|
+
* @param random Seeded random generator.
|
|
22729
|
+
* @param palette Derived avatar palette.
|
|
22730
|
+
* @param hasHeadband Whether the generated avatar should include a colored headband.
|
|
22731
|
+
* @returns Head cuboid textures.
|
|
22732
|
+
*
|
|
22733
|
+
* @private helper of the Minecraft avatar visuals
|
|
22734
|
+
*/
|
|
22735
|
+
function createMinecraftHeadTextures(random, palette, hasHeadband) {
|
|
22736
|
+
const faceTexture = createMinecraftFaceTexture(random, palette, hasHeadband);
|
|
22737
|
+
const hairColor = random() < 0.5 ? palette.primary : palette.secondary;
|
|
22738
|
+
const skinColor = palette.highlight;
|
|
22739
|
+
const headbandColor = hasHeadband ? palette.accent : hairColor;
|
|
22740
|
+
const sideTexture = createFilledTexture(skinColor);
|
|
22741
|
+
const backTexture = createFilledTexture(skinColor);
|
|
22742
|
+
const topTexture = createFilledTexture(hairColor);
|
|
22743
|
+
const bottomTexture = createFilledTexture(`${palette.shadow}cc`);
|
|
22744
|
+
fillTextureRect(sideTexture, 0, 0, 8, 3, hairColor);
|
|
22745
|
+
fillTextureRect(backTexture, 0, 0, 8, 5, hairColor);
|
|
22746
|
+
fillTextureRect(backTexture, 1, 5, 6, 1, hairColor);
|
|
22747
|
+
if (hasHeadband) {
|
|
22748
|
+
fillTextureRect(sideTexture, 0, 2, 8, 1, headbandColor);
|
|
22749
|
+
fillTextureRect(backTexture, 0, 2, 8, 1, headbandColor);
|
|
22750
|
+
fillTextureRect(topTexture, 0, 4, 8, 1, headbandColor);
|
|
22751
|
+
}
|
|
22752
|
+
sideTexture[4][4] = `${palette.shadow}99`;
|
|
22753
|
+
sideTexture[5][4] = `${palette.shadow}cc`;
|
|
22754
|
+
backTexture[6][2] = `${palette.shadow}99`;
|
|
22755
|
+
backTexture[6][5] = `${palette.shadow}99`;
|
|
22756
|
+
return {
|
|
22757
|
+
front: faceTexture,
|
|
22758
|
+
back: backTexture,
|
|
22759
|
+
left: sideTexture,
|
|
22760
|
+
right: mirrorMinecraftTexture(sideTexture),
|
|
22761
|
+
top: topTexture,
|
|
22762
|
+
bottom: bottomTexture,
|
|
22763
|
+
};
|
|
22764
|
+
}
|
|
22765
|
+
/**
|
|
22766
|
+
* Builds the seeded six-face texture pack used by the Minecraft-style torso cuboid.
|
|
22767
|
+
*
|
|
22768
|
+
* @param random Seeded random generator.
|
|
22769
|
+
* @param palette Derived avatar palette.
|
|
22770
|
+
* @returns Torso cuboid textures.
|
|
22771
|
+
*
|
|
22772
|
+
* @private helper of the Minecraft avatar visuals
|
|
22773
|
+
*/
|
|
22774
|
+
function createMinecraftTorsoTextures(random, palette) {
|
|
22775
|
+
const frontTexture = createMinecraftShirtTexture(random, palette);
|
|
22776
|
+
const sideTexture = createFilledTexture(palette.primary);
|
|
22777
|
+
const backTexture = createFilledTexture(palette.primary);
|
|
22778
|
+
const topTexture = createFilledTexture(`${palette.highlight}dd`);
|
|
22779
|
+
const bottomTexture = createFilledTexture(`${palette.shadow}dd`);
|
|
22780
|
+
const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
|
|
22781
|
+
fillTextureRect(sideTexture, 0, 0, 8, 2, palette.shadow);
|
|
22782
|
+
fillTextureRect(backTexture, 0, 0, 8, 2, palette.shadow);
|
|
22783
|
+
fillTextureRect(backTexture, 3, 2, 2, 6, stripeColor);
|
|
22784
|
+
fillTextureRect(sideTexture, 4, 2, 1, 6, stripeColor);
|
|
22785
|
+
fillTextureRect(topTexture, 0, 0, 8, 2, palette.shadow);
|
|
22786
|
+
fillTextureRect(topTexture, 2, 2, 4, 4, stripeColor);
|
|
22787
|
+
return {
|
|
22788
|
+
front: frontTexture,
|
|
22789
|
+
back: backTexture,
|
|
22790
|
+
left: sideTexture,
|
|
22791
|
+
right: mirrorMinecraftTexture(sideTexture),
|
|
22792
|
+
top: topTexture,
|
|
22793
|
+
bottom: bottomTexture,
|
|
22794
|
+
};
|
|
22795
|
+
}
|
|
22796
|
+
/**
|
|
22797
|
+
* Mirrors one Minecraft texture horizontally.
|
|
22798
|
+
*
|
|
22799
|
+
* @param texture Source texture.
|
|
22800
|
+
* @returns Mirrored texture copy.
|
|
22801
|
+
*
|
|
22802
|
+
* @private helper of the Minecraft avatar visuals
|
|
22803
|
+
*/
|
|
22804
|
+
function mirrorMinecraftTexture(texture) {
|
|
22805
|
+
return texture.map((row) => [...row].reverse());
|
|
22806
|
+
}
|
|
22807
|
+
/**
|
|
22808
|
+
* Creates the front-face pixel texture for the cube head.
|
|
22809
|
+
*
|
|
22810
|
+
* @param random Seeded random generator.
|
|
22811
|
+
* @param palette Derived avatar palette.
|
|
22812
|
+
* @param hasHeadband Whether the avatar should render a headband row.
|
|
22813
|
+
* @returns 8x8 pixel texture.
|
|
22814
|
+
*
|
|
22815
|
+
* @private helper of the Minecraft avatar visuals
|
|
22816
|
+
*/
|
|
22817
|
+
function createMinecraftFaceTexture(random, palette, hasHeadband) {
|
|
22818
|
+
const texture = createFilledTexture(palette.highlight);
|
|
22819
|
+
const hairlineColor = random() < 0.5 ? palette.primary : palette.secondary;
|
|
22820
|
+
const cheekColor = random() < 0.5 ? `${palette.accent}bb` : `${palette.secondary}bb`;
|
|
22821
|
+
fillTextureRect(texture, 0, 0, 8, 2, hairlineColor);
|
|
22822
|
+
texture[2][0] = hairlineColor;
|
|
22823
|
+
texture[2][7] = hairlineColor;
|
|
22824
|
+
texture[3][0] = hairlineColor;
|
|
22825
|
+
texture[3][7] = hairlineColor;
|
|
22826
|
+
if (hasHeadband) {
|
|
22827
|
+
fillTextureRect(texture, 0, 2, 8, 1, palette.accent);
|
|
22828
|
+
}
|
|
22829
|
+
texture[3][2] = palette.ink;
|
|
22830
|
+
texture[3][5] = palette.ink;
|
|
22831
|
+
texture[4][2] = '#ffffff';
|
|
22832
|
+
texture[4][5] = '#ffffff';
|
|
22833
|
+
texture[5][1] = cheekColor;
|
|
22834
|
+
texture[5][6] = cheekColor;
|
|
22835
|
+
texture[5][3] = palette.shadow;
|
|
22836
|
+
texture[5][4] = palette.shadow;
|
|
22837
|
+
texture[6][3] = palette.shadow;
|
|
22838
|
+
texture[6][4] = palette.shadow;
|
|
22839
|
+
return texture;
|
|
22840
|
+
}
|
|
22841
|
+
/**
|
|
22842
|
+
* Creates the front-face pixel texture for the torso.
|
|
22843
|
+
*
|
|
22844
|
+
* @param random Seeded random generator.
|
|
22845
|
+
* @param palette Derived avatar palette.
|
|
22846
|
+
* @returns 8x8 torso texture.
|
|
22847
|
+
*
|
|
22848
|
+
* @private helper of the Minecraft avatar visuals
|
|
22849
|
+
*/
|
|
22850
|
+
function createMinecraftShirtTexture(random, palette) {
|
|
22851
|
+
const texture = createFilledTexture(palette.primary);
|
|
22852
|
+
const stripeColor = random() < 0.5 ? palette.secondary : palette.highlight;
|
|
22853
|
+
fillTextureRect(texture, 0, 0, 8, 2, palette.shadow);
|
|
22854
|
+
for (let rowIndex = 2; rowIndex < 8; rowIndex++) {
|
|
22855
|
+
texture[rowIndex][3] = stripeColor;
|
|
22856
|
+
texture[rowIndex][4] = stripeColor;
|
|
22857
|
+
}
|
|
22858
|
+
texture[4][1] = palette.accent;
|
|
22859
|
+
texture[4][6] = palette.accent;
|
|
22860
|
+
texture[5][2] = palette.highlight;
|
|
22861
|
+
texture[5][5] = palette.highlight;
|
|
22862
|
+
return texture;
|
|
22863
|
+
}
|
|
22864
|
+
/**
|
|
22865
|
+
* Creates one solid-color 8x8 Minecraft texture.
|
|
22866
|
+
*
|
|
22867
|
+
* @param color Fill color.
|
|
22868
|
+
* @returns Filled 8x8 texture.
|
|
22869
|
+
*
|
|
22870
|
+
* @private helper of the Minecraft avatar visuals
|
|
22871
|
+
*/
|
|
22872
|
+
function createFilledTexture(color) {
|
|
22873
|
+
return Array.from({ length: 8 }, () => Array.from({ length: 8 }, () => color));
|
|
22874
|
+
}
|
|
22875
|
+
/**
|
|
22876
|
+
* Fills one rectangular area inside a mutable Minecraft texture.
|
|
22877
|
+
*
|
|
22878
|
+
* @param texture Mutable target texture.
|
|
22879
|
+
* @param x Left texture coordinate.
|
|
22880
|
+
* @param y Top texture coordinate.
|
|
22881
|
+
* @param width Rectangle width.
|
|
22882
|
+
* @param height Rectangle height.
|
|
22883
|
+
* @param color Fill color.
|
|
22884
|
+
*
|
|
22885
|
+
* @private helper of the Minecraft avatar visuals
|
|
22886
|
+
*/
|
|
22887
|
+
function fillTextureRect(texture, x, y, width, height, color) {
|
|
22888
|
+
for (let rowIndex = y; rowIndex < y + height; rowIndex++) {
|
|
22889
|
+
for (let columnIndex = x; columnIndex < x + width; columnIndex++) {
|
|
22890
|
+
texture[rowIndex][columnIndex] = color;
|
|
22891
|
+
}
|
|
22892
|
+
}
|
|
22893
|
+
}
|
|
22894
|
+
|
|
22691
22895
|
/* eslint-disable no-magic-numbers */
|
|
22692
22896
|
/**
|
|
22693
22897
|
* Minecraft-style 3D avatar visual.
|
|
@@ -22712,8 +22916,8 @@ const minecraftAvatarVisual = {
|
|
|
22712
22916
|
const bodyX = size * 0.33;
|
|
22713
22917
|
const bodyY = headY + headSize * 0.96;
|
|
22714
22918
|
const hasHeadband = random() < 0.5;
|
|
22715
|
-
const
|
|
22716
|
-
const
|
|
22919
|
+
const headTextures = createMinecraftHeadTextures(createRandom('minecraft-face'), palette, hasHeadband);
|
|
22920
|
+
const torsoTextures = createMinecraftTorsoTextures(createRandom('minecraft-shirt'), palette);
|
|
22717
22921
|
drawAvatarFrame(context, size, palette);
|
|
22718
22922
|
const spotlight = context.createRadialGradient(size * 0.5, size * 0.18, size * 0.05, size * 0.5, size * 0.18, size * 0.5);
|
|
22719
22923
|
spotlight.addColorStop(0, `${palette.highlight}66`);
|
|
@@ -22733,7 +22937,7 @@ const minecraftAvatarVisual = {
|
|
|
22733
22937
|
width: bodyWidth,
|
|
22734
22938
|
height: bodyHeight,
|
|
22735
22939
|
depth: bodyDepth,
|
|
22736
|
-
frontTexture:
|
|
22940
|
+
frontTexture: torsoTextures.front,
|
|
22737
22941
|
topColor: `${palette.highlight}cc`,
|
|
22738
22942
|
sideColor: `${palette.secondary}dd`,
|
|
22739
22943
|
outlineColor: `${palette.shadow}aa`,
|
|
@@ -22744,7 +22948,7 @@ const minecraftAvatarVisual = {
|
|
|
22744
22948
|
width: headSize,
|
|
22745
22949
|
height: headSize,
|
|
22746
22950
|
depth,
|
|
22747
|
-
frontTexture:
|
|
22951
|
+
frontTexture: headTextures.front,
|
|
22748
22952
|
topColor: `${palette.highlight}ee`,
|
|
22749
22953
|
sideColor: `${palette.secondary}ee`,
|
|
22750
22954
|
outlineColor: `${palette.shadow}cc`,
|
|
@@ -22809,72 +23013,505 @@ function drawVoxelCuboid(context, cuboid) {
|
|
|
22809
23013
|
context.closePath();
|
|
22810
23014
|
context.stroke();
|
|
22811
23015
|
}
|
|
23016
|
+
|
|
23017
|
+
/* eslint-disable no-magic-numbers */
|
|
22812
23018
|
/**
|
|
22813
|
-
*
|
|
23019
|
+
* Fixed scene camera distance used for the proper-3D projection.
|
|
22814
23020
|
*
|
|
22815
|
-
* @
|
|
23021
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23022
|
+
*/
|
|
23023
|
+
const CAMERA_DISTANCE_RATIO = 1.4;
|
|
23024
|
+
/**
|
|
23025
|
+
* Shared light direction used to shade projected cuboid faces.
|
|
23026
|
+
*
|
|
23027
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23028
|
+
*/
|
|
23029
|
+
const LIGHT_DIRECTION = normalizeVector3({
|
|
23030
|
+
x: 0.4,
|
|
23031
|
+
y: -0.65,
|
|
23032
|
+
z: 0.92,
|
|
23033
|
+
});
|
|
23034
|
+
/**
|
|
23035
|
+
* Minecraft 3D 2 avatar visual.
|
|
23036
|
+
*
|
|
23037
|
+
* @private built-in avatar visual
|
|
23038
|
+
*/
|
|
23039
|
+
const minecraft2AvatarVisual = {
|
|
23040
|
+
id: 'minecraft2',
|
|
23041
|
+
title: 'Minecraft 3D 2',
|
|
23042
|
+
description: 'Proper 3D Minecraft-style portrait with textured cuboids and pointer-driven head turns.',
|
|
23043
|
+
isAnimated: true,
|
|
23044
|
+
supportsPointerTracking: true,
|
|
23045
|
+
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
23046
|
+
const spotlightY = size * 0.22;
|
|
23047
|
+
const headRandom = createRandom('minecraft2-head');
|
|
23048
|
+
const hasHeadband = headRandom() < 0.5;
|
|
23049
|
+
const headTextures = createMinecraftHeadTextures(createRandom('minecraft2-head-textures'), palette, hasHeadband);
|
|
23050
|
+
const torsoTextures = createMinecraftTorsoTextures(createRandom('minecraft2-body-textures'), palette);
|
|
23051
|
+
const bob = Math.sin(timeMs / 880) * size * 0.014;
|
|
23052
|
+
const bodyYaw = -0.24 + Math.sin(timeMs / 2300) * 0.06 + interaction.bodyOffsetX * 0.16;
|
|
23053
|
+
const bodyPitch = -0.12 + Math.cos(timeMs / 2800) * 0.02 - interaction.bodyOffsetY * 0.06;
|
|
23054
|
+
const headYaw = -0.18 + Math.sin(timeMs / 1900 + 0.6) * 0.05 + interaction.gazeX * 0.62;
|
|
23055
|
+
const headPitch = -0.12 + Math.cos(timeMs / 2400 + 1.1) * 0.03 - interaction.gazeY * 0.38;
|
|
23056
|
+
const sceneCenterX = size * 0.5;
|
|
23057
|
+
const sceneCenterY = size * 0.57;
|
|
23058
|
+
const bodyWidth = size * 0.225;
|
|
23059
|
+
const bodyHeight = size * 0.245;
|
|
23060
|
+
const bodyDepth = size * 0.145;
|
|
23061
|
+
const headSize = size * 0.24;
|
|
23062
|
+
const headLift = size * 0.205;
|
|
23063
|
+
const headForwardShift = interaction.intensity * size * 0.018;
|
|
23064
|
+
const sceneCuboids = [
|
|
23065
|
+
{
|
|
23066
|
+
center: {
|
|
23067
|
+
x: interaction.bodyOffsetX * size * 0.026,
|
|
23068
|
+
y: size * 0.05 + interaction.bodyOffsetY * size * 0.018 + bob,
|
|
23069
|
+
z: 0,
|
|
23070
|
+
},
|
|
23071
|
+
width: bodyWidth,
|
|
23072
|
+
height: bodyHeight,
|
|
23073
|
+
depth: bodyDepth,
|
|
23074
|
+
rotationX: bodyPitch,
|
|
23075
|
+
rotationY: bodyYaw,
|
|
23076
|
+
textures: torsoTextures,
|
|
23077
|
+
outlineColor: `${palette.shadow}cc`,
|
|
23078
|
+
},
|
|
23079
|
+
{
|
|
23080
|
+
center: {
|
|
23081
|
+
x: interaction.bodyOffsetX * size * 0.018 + interaction.gazeX * size * 0.016,
|
|
23082
|
+
y: -headLift + bob * 1.15,
|
|
23083
|
+
z: headForwardShift,
|
|
23084
|
+
},
|
|
23085
|
+
width: headSize,
|
|
23086
|
+
height: headSize,
|
|
23087
|
+
depth: headSize,
|
|
23088
|
+
rotationX: headPitch,
|
|
23089
|
+
rotationY: headYaw,
|
|
23090
|
+
textures: headTextures,
|
|
23091
|
+
outlineColor: `${palette.shadow}dd`,
|
|
23092
|
+
},
|
|
23093
|
+
];
|
|
23094
|
+
const visibleFaces = sceneCuboids
|
|
23095
|
+
.flatMap((cuboid) => resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY))
|
|
23096
|
+
.sort((firstFace, secondFace) => firstFace.averageDepth - secondFace.averageDepth);
|
|
23097
|
+
drawAvatarFrame(context, size, palette);
|
|
23098
|
+
drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY, interaction, timeMs);
|
|
23099
|
+
drawMinecraftShadow(context, size, palette, interaction, timeMs);
|
|
23100
|
+
for (const visibleFace of visibleFaces) {
|
|
23101
|
+
drawTexturedProjectedFace(context, visibleFace);
|
|
23102
|
+
}
|
|
23103
|
+
},
|
|
23104
|
+
};
|
|
23105
|
+
/**
|
|
23106
|
+
* Draws the shared background atmosphere behind the Minecraft 3D 2 portrait.
|
|
23107
|
+
*
|
|
23108
|
+
* @param context Canvas 2D context.
|
|
23109
|
+
* @param size Canvas size in CSS pixels.
|
|
22816
23110
|
* @param palette Derived avatar palette.
|
|
22817
|
-
* @param
|
|
22818
|
-
* @
|
|
23111
|
+
* @param sceneCenterX Horizontal scene center.
|
|
23112
|
+
* @param spotlightY Vertical spotlight anchor.
|
|
23113
|
+
* @param interaction Smoothed pointer-aware interaction state.
|
|
23114
|
+
* @param timeMs Current animation time in milliseconds.
|
|
22819
23115
|
*
|
|
22820
|
-
* @private helper of `
|
|
23116
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
22821
23117
|
*/
|
|
22822
|
-
function
|
|
22823
|
-
const
|
|
22824
|
-
|
|
22825
|
-
|
|
22826
|
-
|
|
22827
|
-
|
|
22828
|
-
|
|
23118
|
+
function drawMinecraftBackdrop(context, size, palette, sceneCenterX, spotlightY, interaction, timeMs) {
|
|
23119
|
+
const spotlightGradient = context.createRadialGradient(sceneCenterX + interaction.gazeX * size * 0.08, spotlightY + interaction.gazeY * size * 0.05, size * 0.03, sceneCenterX, spotlightY, size * 0.52);
|
|
23120
|
+
spotlightGradient.addColorStop(0, `${palette.highlight}66`);
|
|
23121
|
+
spotlightGradient.addColorStop(0.42, `${palette.accent}1d`);
|
|
23122
|
+
spotlightGradient.addColorStop(1, `${palette.highlight}00`);
|
|
23123
|
+
context.fillStyle = spotlightGradient;
|
|
23124
|
+
context.fillRect(0, 0, size, size);
|
|
23125
|
+
const rimGradient = context.createLinearGradient(0, size * 0.14, 0, size * 0.92);
|
|
23126
|
+
rimGradient.addColorStop(0, `${palette.highlight}12`);
|
|
23127
|
+
rimGradient.addColorStop(0.55, `${palette.secondary}0a`);
|
|
23128
|
+
rimGradient.addColorStop(1, `${palette.shadow}00`);
|
|
23129
|
+
context.fillStyle = rimGradient;
|
|
23130
|
+
context.fillRect(0, 0, size, size);
|
|
23131
|
+
context.save();
|
|
23132
|
+
context.globalAlpha = 0.08 + interaction.intensity * 0.04;
|
|
23133
|
+
context.fillStyle = palette.highlight;
|
|
23134
|
+
context.beginPath();
|
|
23135
|
+
context.arc(size * 0.72 + Math.sin(timeMs / 1600) * size * 0.03, size * 0.2 + Math.cos(timeMs / 1400) * size * 0.018, size * 0.025, 0, Math.PI * 2);
|
|
23136
|
+
context.fill();
|
|
23137
|
+
context.restore();
|
|
23138
|
+
}
|
|
23139
|
+
/**
|
|
23140
|
+
* Draws the soft floor shadow used to anchor the cuboids in the frame.
|
|
23141
|
+
*
|
|
23142
|
+
* @param context Canvas 2D context.
|
|
23143
|
+
* @param size Canvas size in CSS pixels.
|
|
23144
|
+
* @param palette Derived avatar palette.
|
|
23145
|
+
* @param interaction Smoothed pointer-aware interaction state.
|
|
23146
|
+
* @param timeMs Current animation time in milliseconds.
|
|
23147
|
+
*
|
|
23148
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23149
|
+
*/
|
|
23150
|
+
function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
|
|
23151
|
+
context.save();
|
|
23152
|
+
context.fillStyle = `${palette.shadow}66`;
|
|
23153
|
+
context.filter = `blur(${size * 0.02}px)`;
|
|
23154
|
+
context.beginPath();
|
|
23155
|
+
context.ellipse(size * 0.5 + interaction.gazeX * size * 0.03, size * 0.85 + Math.sin(timeMs / 880) * size * 0.01, size * (0.16 + interaction.intensity * 0.015), size * 0.055, 0, 0, Math.PI * 2);
|
|
23156
|
+
context.fill();
|
|
23157
|
+
context.restore();
|
|
23158
|
+
}
|
|
23159
|
+
/**
|
|
23160
|
+
* Resolves all visible projected faces for one scene cuboid.
|
|
23161
|
+
*
|
|
23162
|
+
* @param cuboid Scene cuboid definition.
|
|
23163
|
+
* @param size Canvas size in CSS pixels.
|
|
23164
|
+
* @param sceneCenterX Horizontal scene center.
|
|
23165
|
+
* @param sceneCenterY Vertical scene center.
|
|
23166
|
+
* @returns Visible faces sorted later by depth.
|
|
23167
|
+
*
|
|
23168
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23169
|
+
*/
|
|
23170
|
+
function resolveVisibleCuboidFaces(cuboid, size, sceneCenterX, sceneCenterY) {
|
|
23171
|
+
const halfWidth = cuboid.width / 2;
|
|
23172
|
+
const halfHeight = cuboid.height / 2;
|
|
23173
|
+
const halfDepth = cuboid.depth / 2;
|
|
23174
|
+
const faceDefinitions = [
|
|
23175
|
+
{
|
|
23176
|
+
texture: cuboid.textures.front,
|
|
23177
|
+
corners: [
|
|
23178
|
+
{ x: -halfWidth, y: -halfHeight, z: halfDepth },
|
|
23179
|
+
{ x: halfWidth, y: -halfHeight, z: halfDepth },
|
|
23180
|
+
{ x: halfWidth, y: halfHeight, z: halfDepth },
|
|
23181
|
+
{ x: -halfWidth, y: halfHeight, z: halfDepth },
|
|
23182
|
+
],
|
|
23183
|
+
},
|
|
23184
|
+
{
|
|
23185
|
+
texture: cuboid.textures.back,
|
|
23186
|
+
corners: [
|
|
23187
|
+
{ x: halfWidth, y: -halfHeight, z: -halfDepth },
|
|
23188
|
+
{ x: -halfWidth, y: -halfHeight, z: -halfDepth },
|
|
23189
|
+
{ x: -halfWidth, y: halfHeight, z: -halfDepth },
|
|
23190
|
+
{ x: halfWidth, y: halfHeight, z: -halfDepth },
|
|
23191
|
+
],
|
|
23192
|
+
},
|
|
23193
|
+
{
|
|
23194
|
+
texture: cuboid.textures.right,
|
|
23195
|
+
corners: [
|
|
23196
|
+
{ x: halfWidth, y: -halfHeight, z: halfDepth },
|
|
23197
|
+
{ x: halfWidth, y: -halfHeight, z: -halfDepth },
|
|
23198
|
+
{ x: halfWidth, y: halfHeight, z: -halfDepth },
|
|
23199
|
+
{ x: halfWidth, y: halfHeight, z: halfDepth },
|
|
23200
|
+
],
|
|
23201
|
+
},
|
|
23202
|
+
{
|
|
23203
|
+
texture: cuboid.textures.left,
|
|
23204
|
+
corners: [
|
|
23205
|
+
{ x: -halfWidth, y: -halfHeight, z: -halfDepth },
|
|
23206
|
+
{ x: -halfWidth, y: -halfHeight, z: halfDepth },
|
|
23207
|
+
{ x: -halfWidth, y: halfHeight, z: halfDepth },
|
|
23208
|
+
{ x: -halfWidth, y: halfHeight, z: -halfDepth },
|
|
23209
|
+
],
|
|
23210
|
+
},
|
|
23211
|
+
{
|
|
23212
|
+
texture: cuboid.textures.top,
|
|
23213
|
+
corners: [
|
|
23214
|
+
{ x: -halfWidth, y: -halfHeight, z: -halfDepth },
|
|
23215
|
+
{ x: halfWidth, y: -halfHeight, z: -halfDepth },
|
|
23216
|
+
{ x: halfWidth, y: -halfHeight, z: halfDepth },
|
|
23217
|
+
{ x: -halfWidth, y: -halfHeight, z: halfDepth },
|
|
23218
|
+
],
|
|
23219
|
+
},
|
|
23220
|
+
{
|
|
23221
|
+
texture: cuboid.textures.bottom,
|
|
23222
|
+
corners: [
|
|
23223
|
+
{ x: -halfWidth, y: halfHeight, z: halfDepth },
|
|
23224
|
+
{ x: halfWidth, y: halfHeight, z: halfDepth },
|
|
23225
|
+
{ x: halfWidth, y: halfHeight, z: -halfDepth },
|
|
23226
|
+
{ x: -halfWidth, y: halfHeight, z: -halfDepth },
|
|
23227
|
+
],
|
|
23228
|
+
},
|
|
23229
|
+
];
|
|
23230
|
+
const visibleFaces = faceDefinitions
|
|
23231
|
+
.map((faceDefinition) => {
|
|
23232
|
+
const transformedCorners = faceDefinition.corners.map((corner) => transformScenePoint(corner, cuboid.center, cuboid.rotationX, cuboid.rotationY));
|
|
23233
|
+
const faceNormal = normalizeVector3(crossProduct3D(subtractPoint3D(transformedCorners[1], transformedCorners[0]), subtractPoint3D(transformedCorners[2], transformedCorners[0])));
|
|
23234
|
+
if (faceNormal.z <= 0.02) {
|
|
23235
|
+
return null;
|
|
22829
23236
|
}
|
|
23237
|
+
const projectedCorners = transformedCorners.map((corner) => projectScenePoint(corner, size, sceneCenterX, sceneCenterY));
|
|
23238
|
+
return {
|
|
23239
|
+
corners: projectedCorners,
|
|
23240
|
+
texture: faceDefinition.texture,
|
|
23241
|
+
averageDepth: transformedCorners.reduce((depthSum, corner) => depthSum + corner.z, 0) / transformedCorners.length,
|
|
23242
|
+
lightIntensity: clampNumber$1(dotProduct3D(faceNormal, LIGHT_DIRECTION), -1, 1),
|
|
23243
|
+
outlineColor: cuboid.outlineColor,
|
|
23244
|
+
};
|
|
23245
|
+
});
|
|
23246
|
+
return visibleFaces.filter((visibleFace) => visibleFace !== null);
|
|
23247
|
+
}
|
|
23248
|
+
/**
|
|
23249
|
+
* Draws one projected textured face by tessellating its texture cells into quads.
|
|
23250
|
+
*
|
|
23251
|
+
* @param context Canvas 2D context.
|
|
23252
|
+
* @param face Visible projected face.
|
|
23253
|
+
*
|
|
23254
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23255
|
+
*/
|
|
23256
|
+
function drawTexturedProjectedFace(context, face) {
|
|
23257
|
+
var _a;
|
|
23258
|
+
const rows = face.texture.length;
|
|
23259
|
+
const columns = ((_a = face.texture[0]) === null || _a === void 0 ? void 0 : _a.length) || 0;
|
|
23260
|
+
if (rows === 0 || columns === 0) {
|
|
23261
|
+
return;
|
|
22830
23262
|
}
|
|
22831
|
-
|
|
22832
|
-
|
|
22833
|
-
|
|
22834
|
-
|
|
22835
|
-
|
|
22836
|
-
|
|
22837
|
-
|
|
23263
|
+
for (let rowIndex = 0; rowIndex < rows; rowIndex++) {
|
|
23264
|
+
for (let columnIndex = 0; columnIndex < columns; columnIndex++) {
|
|
23265
|
+
const startX = columnIndex / columns;
|
|
23266
|
+
const endX = (columnIndex + 1) / columns;
|
|
23267
|
+
const startY = rowIndex / rows;
|
|
23268
|
+
const endY = (rowIndex + 1) / rows;
|
|
23269
|
+
drawProjectedQuad(context, [
|
|
23270
|
+
interpolateProjectedQuad(face.corners, startX, startY),
|
|
23271
|
+
interpolateProjectedQuad(face.corners, endX, startY),
|
|
23272
|
+
interpolateProjectedQuad(face.corners, endX, endY),
|
|
23273
|
+
interpolateProjectedQuad(face.corners, startX, endY),
|
|
23274
|
+
], face.texture[rowIndex][columnIndex]);
|
|
22838
23275
|
}
|
|
22839
23276
|
}
|
|
22840
|
-
|
|
22841
|
-
|
|
22842
|
-
|
|
22843
|
-
|
|
22844
|
-
|
|
22845
|
-
|
|
22846
|
-
|
|
22847
|
-
|
|
22848
|
-
|
|
22849
|
-
|
|
22850
|
-
|
|
23277
|
+
if (face.lightIntensity > 0) {
|
|
23278
|
+
drawProjectedQuad(context, face.corners, `rgba(255, 255, 255, ${0.15 * face.lightIntensity})`);
|
|
23279
|
+
}
|
|
23280
|
+
else if (face.lightIntensity < 0) {
|
|
23281
|
+
drawProjectedQuad(context, face.corners, `rgba(0, 0, 0, ${0.22 * Math.abs(face.lightIntensity)})`);
|
|
23282
|
+
}
|
|
23283
|
+
context.save();
|
|
23284
|
+
context.beginPath();
|
|
23285
|
+
context.moveTo(face.corners[0].x, face.corners[0].y);
|
|
23286
|
+
for (let cornerIndex = 1; cornerIndex < face.corners.length; cornerIndex++) {
|
|
23287
|
+
context.lineTo(face.corners[cornerIndex].x, face.corners[cornerIndex].y);
|
|
23288
|
+
}
|
|
23289
|
+
context.closePath();
|
|
23290
|
+
context.strokeStyle = face.outlineColor;
|
|
23291
|
+
context.lineWidth = Math.max(1.1, getProjectedQuadPerimeter(face.corners) * 0.0045);
|
|
23292
|
+
context.lineJoin = 'round';
|
|
23293
|
+
context.stroke();
|
|
23294
|
+
context.restore();
|
|
22851
23295
|
}
|
|
22852
23296
|
/**
|
|
22853
|
-
*
|
|
23297
|
+
* Draws one filled projected quad.
|
|
22854
23298
|
*
|
|
22855
|
-
* @param
|
|
22856
|
-
* @param
|
|
22857
|
-
* @
|
|
23299
|
+
* @param context Canvas 2D context.
|
|
23300
|
+
* @param corners Quad corners in clockwise order.
|
|
23301
|
+
* @param fillStyle CSS fill style.
|
|
22858
23302
|
*
|
|
22859
|
-
* @private helper of `
|
|
23303
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
22860
23304
|
*/
|
|
22861
|
-
function
|
|
22862
|
-
|
|
22863
|
-
|
|
22864
|
-
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
23305
|
+
function drawProjectedQuad(context, corners, fillStyle) {
|
|
23306
|
+
context.beginPath();
|
|
23307
|
+
context.moveTo(corners[0].x, corners[0].y);
|
|
23308
|
+
context.lineTo(corners[1].x, corners[1].y);
|
|
23309
|
+
context.lineTo(corners[2].x, corners[2].y);
|
|
23310
|
+
context.lineTo(corners[3].x, corners[3].y);
|
|
23311
|
+
context.closePath();
|
|
23312
|
+
context.fillStyle = fillStyle;
|
|
23313
|
+
context.fill();
|
|
23314
|
+
}
|
|
23315
|
+
/**
|
|
23316
|
+
* Interpolates one point inside a projected quad across both quad axes.
|
|
23317
|
+
*
|
|
23318
|
+
* @param corners Quad corners in clockwise order.
|
|
23319
|
+
* @param horizontalRatio Horizontal ratio in the range `[0, 1]`.
|
|
23320
|
+
* @param verticalRatio Vertical ratio in the range `[0, 1]`.
|
|
23321
|
+
* @returns Interpolated projected point.
|
|
23322
|
+
*
|
|
23323
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23324
|
+
*/
|
|
23325
|
+
function interpolateProjectedQuad(corners, horizontalRatio, verticalRatio) {
|
|
23326
|
+
const topPoint = interpolateProjectedPoint(corners[0], corners[1], horizontalRatio);
|
|
23327
|
+
const bottomPoint = interpolateProjectedPoint(corners[3], corners[2], horizontalRatio);
|
|
23328
|
+
return interpolateProjectedPoint(topPoint, bottomPoint, verticalRatio);
|
|
23329
|
+
}
|
|
23330
|
+
/**
|
|
23331
|
+
* Interpolates between two projected points.
|
|
23332
|
+
*
|
|
23333
|
+
* @param startPoint Start point.
|
|
23334
|
+
* @param endPoint End point.
|
|
23335
|
+
* @param ratio Interpolation ratio in the range `[0, 1]`.
|
|
23336
|
+
* @returns Interpolated projected point.
|
|
23337
|
+
*
|
|
23338
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23339
|
+
*/
|
|
23340
|
+
function interpolateProjectedPoint(startPoint, endPoint, ratio) {
|
|
23341
|
+
return {
|
|
23342
|
+
x: startPoint.x + (endPoint.x - startPoint.x) * ratio,
|
|
23343
|
+
y: startPoint.y + (endPoint.y - startPoint.y) * ratio,
|
|
23344
|
+
z: startPoint.z + (endPoint.z - startPoint.z) * ratio,
|
|
23345
|
+
};
|
|
23346
|
+
}
|
|
23347
|
+
/**
|
|
23348
|
+
* Projects one rotated scene point into canvas coordinates.
|
|
23349
|
+
*
|
|
23350
|
+
* @param point Scene point.
|
|
23351
|
+
* @param size Canvas size in CSS pixels.
|
|
23352
|
+
* @param sceneCenterX Horizontal scene center.
|
|
23353
|
+
* @param sceneCenterY Vertical scene center.
|
|
23354
|
+
* @returns Projected point.
|
|
23355
|
+
*
|
|
23356
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23357
|
+
*/
|
|
23358
|
+
function projectScenePoint(point, size, sceneCenterX, sceneCenterY) {
|
|
23359
|
+
const cameraDistance = size * CAMERA_DISTANCE_RATIO;
|
|
23360
|
+
const perspectiveScale = cameraDistance / Math.max(cameraDistance - point.z, cameraDistance * 0.35);
|
|
23361
|
+
return {
|
|
23362
|
+
x: sceneCenterX + point.x * perspectiveScale,
|
|
23363
|
+
y: sceneCenterY + point.y * perspectiveScale,
|
|
23364
|
+
z: point.z,
|
|
23365
|
+
};
|
|
23366
|
+
}
|
|
23367
|
+
/**
|
|
23368
|
+
* Applies the local cuboid rotations and translation to one scene point.
|
|
23369
|
+
*
|
|
23370
|
+
* @param localPoint Point in cuboid-local space.
|
|
23371
|
+
* @param center Cuboid center in scene space.
|
|
23372
|
+
* @param rotationX Cuboid pitch in radians.
|
|
23373
|
+
* @param rotationY Cuboid yaw in radians.
|
|
23374
|
+
* @returns Transformed scene-space point.
|
|
23375
|
+
*
|
|
23376
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23377
|
+
*/
|
|
23378
|
+
function transformScenePoint(localPoint, center, rotationX, rotationY) {
|
|
23379
|
+
const yawedPoint = rotatePointAroundY(localPoint, rotationY);
|
|
23380
|
+
const pitchedPoint = rotatePointAroundX(yawedPoint, rotationX);
|
|
23381
|
+
return {
|
|
23382
|
+
x: center.x + pitchedPoint.x,
|
|
23383
|
+
y: center.y + pitchedPoint.y,
|
|
23384
|
+
z: center.z + pitchedPoint.z,
|
|
23385
|
+
};
|
|
23386
|
+
}
|
|
23387
|
+
/**
|
|
23388
|
+
* Rotates one point around the local Y axis.
|
|
23389
|
+
*
|
|
23390
|
+
* @param point Source point.
|
|
23391
|
+
* @param angle Rotation angle in radians.
|
|
23392
|
+
* @returns Rotated point.
|
|
23393
|
+
*
|
|
23394
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23395
|
+
*/
|
|
23396
|
+
function rotatePointAroundY(point, angle) {
|
|
23397
|
+
const cosine = Math.cos(angle);
|
|
23398
|
+
const sine = Math.sin(angle);
|
|
23399
|
+
return {
|
|
23400
|
+
x: point.x * cosine + point.z * sine,
|
|
23401
|
+
y: point.y,
|
|
23402
|
+
z: -point.x * sine + point.z * cosine,
|
|
23403
|
+
};
|
|
23404
|
+
}
|
|
23405
|
+
/**
|
|
23406
|
+
* Rotates one point around the local X axis.
|
|
23407
|
+
*
|
|
23408
|
+
* @param point Source point.
|
|
23409
|
+
* @param angle Rotation angle in radians.
|
|
23410
|
+
* @returns Rotated point.
|
|
23411
|
+
*
|
|
23412
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23413
|
+
*/
|
|
23414
|
+
function rotatePointAroundX(point, angle) {
|
|
23415
|
+
const cosine = Math.cos(angle);
|
|
23416
|
+
const sine = Math.sin(angle);
|
|
23417
|
+
return {
|
|
23418
|
+
x: point.x,
|
|
23419
|
+
y: point.y * cosine - point.z * sine,
|
|
23420
|
+
z: point.y * sine + point.z * cosine,
|
|
23421
|
+
};
|
|
23422
|
+
}
|
|
23423
|
+
/**
|
|
23424
|
+
* Subtracts one 3D point from another.
|
|
23425
|
+
*
|
|
23426
|
+
* @param leftPoint Left point.
|
|
23427
|
+
* @param rightPoint Right point.
|
|
23428
|
+
* @returns Difference vector.
|
|
23429
|
+
*
|
|
23430
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23431
|
+
*/
|
|
23432
|
+
function subtractPoint3D(leftPoint, rightPoint) {
|
|
23433
|
+
return {
|
|
23434
|
+
x: leftPoint.x - rightPoint.x,
|
|
23435
|
+
y: leftPoint.y - rightPoint.y,
|
|
23436
|
+
z: leftPoint.z - rightPoint.z,
|
|
23437
|
+
};
|
|
23438
|
+
}
|
|
23439
|
+
/**
|
|
23440
|
+
* Computes the 3D cross product of two vectors.
|
|
23441
|
+
*
|
|
23442
|
+
* @param leftVector Left vector.
|
|
23443
|
+
* @param rightVector Right vector.
|
|
23444
|
+
* @returns Cross product.
|
|
23445
|
+
*
|
|
23446
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23447
|
+
*/
|
|
23448
|
+
function crossProduct3D(leftVector, rightVector) {
|
|
23449
|
+
return {
|
|
23450
|
+
x: leftVector.y * rightVector.z - leftVector.z * rightVector.y,
|
|
23451
|
+
y: leftVector.z * rightVector.x - leftVector.x * rightVector.z,
|
|
23452
|
+
z: leftVector.x * rightVector.y - leftVector.y * rightVector.x,
|
|
23453
|
+
};
|
|
23454
|
+
}
|
|
23455
|
+
/**
|
|
23456
|
+
* Computes the 3D dot product of two vectors.
|
|
23457
|
+
*
|
|
23458
|
+
* @param leftVector Left vector.
|
|
23459
|
+
* @param rightVector Right vector.
|
|
23460
|
+
* @returns Dot product.
|
|
23461
|
+
*
|
|
23462
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23463
|
+
*/
|
|
23464
|
+
function dotProduct3D(leftVector, rightVector) {
|
|
23465
|
+
return leftVector.x * rightVector.x + leftVector.y * rightVector.y + leftVector.z * rightVector.z;
|
|
23466
|
+
}
|
|
23467
|
+
/**
|
|
23468
|
+
* Normalizes one 3D vector while keeping zero vectors stable.
|
|
23469
|
+
*
|
|
23470
|
+
* @param vector Source vector.
|
|
23471
|
+
* @returns Normalized vector.
|
|
23472
|
+
*
|
|
23473
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23474
|
+
*/
|
|
23475
|
+
function normalizeVector3(vector) {
|
|
23476
|
+
const length = Math.hypot(vector.x, vector.y, vector.z);
|
|
23477
|
+
if (length === 0) {
|
|
23478
|
+
return vector;
|
|
22868
23479
|
}
|
|
22869
|
-
|
|
22870
|
-
|
|
22871
|
-
|
|
23480
|
+
return {
|
|
23481
|
+
x: vector.x / length,
|
|
23482
|
+
y: vector.y / length,
|
|
23483
|
+
z: vector.z / length,
|
|
23484
|
+
};
|
|
23485
|
+
}
|
|
23486
|
+
/**
|
|
23487
|
+
* Clamps one number into the provided range.
|
|
23488
|
+
*
|
|
23489
|
+
* @param value Input value.
|
|
23490
|
+
* @param minimumValue Inclusive lower bound.
|
|
23491
|
+
* @param maximumValue Inclusive upper bound.
|
|
23492
|
+
* @returns Clamped value.
|
|
23493
|
+
*
|
|
23494
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23495
|
+
*/
|
|
23496
|
+
function clampNumber$1(value, minimumValue, maximumValue) {
|
|
23497
|
+
return Math.min(maximumValue, Math.max(minimumValue, value));
|
|
23498
|
+
}
|
|
23499
|
+
/**
|
|
23500
|
+
* Measures the perimeter of one projected quad.
|
|
23501
|
+
*
|
|
23502
|
+
* @param corners Quad corners.
|
|
23503
|
+
* @returns Perimeter length.
|
|
23504
|
+
*
|
|
23505
|
+
* @private helper of `minecraft2AvatarVisual`
|
|
23506
|
+
*/
|
|
23507
|
+
function getProjectedQuadPerimeter(corners) {
|
|
23508
|
+
let perimeter = 0;
|
|
23509
|
+
for (let cornerIndex = 0; cornerIndex < corners.length; cornerIndex++) {
|
|
23510
|
+
const currentCorner = corners[cornerIndex];
|
|
23511
|
+
const nextCorner = corners[(cornerIndex + 1) % corners.length];
|
|
23512
|
+
perimeter += Math.hypot(nextCorner.x - currentCorner.x, nextCorner.y - currentCorner.y);
|
|
22872
23513
|
}
|
|
22873
|
-
|
|
22874
|
-
texture[4][6] = palette.accent;
|
|
22875
|
-
texture[5][2] = palette.highlight;
|
|
22876
|
-
texture[5][5] = palette.highlight;
|
|
22877
|
-
return texture;
|
|
23514
|
+
return perimeter;
|
|
22878
23515
|
}
|
|
22879
23516
|
|
|
22880
23517
|
/* eslint-disable no-magic-numbers */
|
|
@@ -24479,6 +25116,7 @@ const AVATAR_VISUALS = [
|
|
|
24479
25116
|
octopus3AvatarVisual,
|
|
24480
25117
|
asciiOctopusAvatarVisual,
|
|
24481
25118
|
minecraftAvatarVisual,
|
|
25119
|
+
minecraft2AvatarVisual,
|
|
24482
25120
|
fractalAvatarVisual,
|
|
24483
25121
|
orbAvatarVisual,
|
|
24484
25122
|
];
|
|
@@ -26687,7 +27325,10 @@ function buildTeamSystemMessageBody(teamEntries) {
|
|
|
26687
27325
|
*/
|
|
26688
27326
|
function buildTeamToolDescription(entry) {
|
|
26689
27327
|
const detailLines = collectTeamEntryDetails(entry).map(({ label, content }) => `${label}: ${content}`);
|
|
26690
|
-
return
|
|
27328
|
+
return spaceTrim$1((block) => `
|
|
27329
|
+
Consult teammate ${entry.teammate.label}
|
|
27330
|
+
${block(detailLines.join('\n'))}
|
|
27331
|
+
`);
|
|
26691
27332
|
}
|
|
26692
27333
|
/**
|
|
26693
27334
|
* Collects structured teammate details that should stay visible to the model.
|
|
@@ -32184,7 +32825,10 @@ function createListedTimeoutsAssistantMessage(options) {
|
|
|
32184
32825
|
if (hiddenCount > 0) {
|
|
32185
32826
|
summaryRows.push(`...and ${hiddenCount} more.`);
|
|
32186
32827
|
}
|
|
32187
|
-
return
|
|
32828
|
+
return spaceTrim$1((block) => `
|
|
32829
|
+
Found ${options.total} ${options.total === 1 ? 'timeout' : 'timeouts'}:
|
|
32830
|
+
${block(summaryRows.join('\n'))}
|
|
32831
|
+
`);
|
|
32188
32832
|
}
|
|
32189
32833
|
/**
|
|
32190
32834
|
* Formats one timeout row for assistant-visible timeout listings.
|
|
@@ -37175,8 +37819,10 @@ async function renderMarkdownServerIndex(runtime) {
|
|
|
37175
37819
|
**Application mode:** ${serverInfo.isApplicationModeAllowed ? 'enabled' : 'disabled'}
|
|
37176
37820
|
${block(!runtime.configuration.isApplicationModeAllowed || runtime.configuration.collection === null
|
|
37177
37821
|
? ''
|
|
37178
|
-
:
|
|
37179
|
-
|
|
37822
|
+
: spaceTrim$1((nestedBlock) => `
|
|
37823
|
+
**Pipelines in collection:**
|
|
37824
|
+
${nestedBlock(serverInfo.pipelines.map((pipelineUrl) => `- ${pipelineUrl}`).join('\n'))}
|
|
37825
|
+
`))}
|
|
37180
37826
|
**Running executions:** ${serverInfo.runningExecutions}
|
|
37181
37827
|
|
|
37182
37828
|
---
|
|
@@ -50905,7 +51551,7 @@ function stringifyUnknownError$2(error) {
|
|
|
50905
51551
|
*/
|
|
50906
51552
|
async function commitChanges(message, options) {
|
|
50907
51553
|
const projectPath = process.cwd();
|
|
50908
|
-
const commitMessagePath =
|
|
51554
|
+
const commitMessagePath = resolvePromptbookTempPath(projectPath, 'scripts', 'codex-prompts', `COMMIT_MESSAGE_${Date.now()}.txt`);
|
|
50909
51555
|
await mkdir(dirname(commitMessagePath), { recursive: true });
|
|
50910
51556
|
await writeFile(commitMessagePath, message, 'utf-8');
|
|
50911
51557
|
try {
|
|
@@ -51873,17 +52519,18 @@ function buildGitHubCopilotScript(options) {
|
|
|
51873
52519
|
|
|
51874
52520
|
unset GITHUB_TOKEN
|
|
51875
52521
|
|
|
51876
|
-
|
|
51877
|
-
|
|
51878
|
-
${block(options.prompt)}
|
|
51879
|
-
|
|
51880
|
-
${delimiter}
|
|
51881
|
-
)" \\
|
|
52522
|
+
# Avoid passing the prompt as one CLI argument because large agent prompts can exceed Windows/MSYS limits.
|
|
52523
|
+
copilot \\
|
|
51882
52524
|
--yolo \\
|
|
51883
52525
|
--no-ask-user \\
|
|
51884
52526
|
--no-color \\
|
|
51885
52527
|
--output-format json \\
|
|
51886
|
-
--stream off${modelArgument}${thinkingLevelArgument}
|
|
52528
|
+
--stream off${modelArgument}${thinkingLevelArgument} \\
|
|
52529
|
+
<<'${delimiter}'
|
|
52530
|
+
|
|
52531
|
+
${block(options.prompt)}
|
|
52532
|
+
|
|
52533
|
+
${delimiter}
|
|
51887
52534
|
`);
|
|
51888
52535
|
}
|
|
51889
52536
|
|
|
@@ -53162,148 +53809,14 @@ function buildCoderRunOctopusVisual(options) {
|
|
|
53162
53809
|
.map((line) => centerAnsiText(line, options.totalWidth));
|
|
53163
53810
|
}
|
|
53164
53811
|
|
|
53165
|
-
/**
|
|
53166
|
-
* Refresh cadence used only while the rich coder UI needs animated updates.
|
|
53167
|
-
*
|
|
53168
|
-
* @private internal constant of coder run UI
|
|
53169
|
-
*/
|
|
53170
|
-
const ACTIVE_CODER_RUN_UI_REFRESH_INTERVAL_MS = 300;
|
|
53171
|
-
/**
|
|
53172
|
-
* Phases that still benefit from automatic refreshes because the frame can change
|
|
53173
|
-
* over time even without new runner output.
|
|
53174
|
-
*
|
|
53175
|
-
* @private internal constant of coder run UI
|
|
53176
|
-
*/
|
|
53177
|
-
const AUTO_REFRESH_PHASES = ['initializing', 'loading', 'running', 'verifying'];
|
|
53178
|
-
/**
|
|
53179
|
-
* Returns whether the rich coder UI should keep animating on its own.
|
|
53180
|
-
*
|
|
53181
|
-
* @private internal utility of coder run UI
|
|
53182
|
-
*/
|
|
53183
|
-
function isCoderRunUiAutoRefreshing(phase, pauseState) {
|
|
53184
|
-
// `PAUSING` still means the current task is winding down, so keep active
|
|
53185
|
-
// animations/timers running until the runner reaches the fully paused state.
|
|
53186
|
-
if (pauseState === 'PAUSED') {
|
|
53187
|
-
return false;
|
|
53188
|
-
}
|
|
53189
|
-
return AUTO_REFRESH_PHASES.includes(phase);
|
|
53190
|
-
}
|
|
53191
|
-
/**
|
|
53192
|
-
* Returns the automatic refresh interval for the current UI state.
|
|
53193
|
-
*
|
|
53194
|
-
* Waiting, paused, and completed states return `undefined` so the rich UI stays
|
|
53195
|
-
* perfectly still until actual state changes arrive.
|
|
53196
|
-
*
|
|
53197
|
-
* @private internal utility of coder run UI
|
|
53198
|
-
*/
|
|
53199
|
-
function getCoderRunUiAutoRefreshInterval(phase, pauseState) {
|
|
53200
|
-
return isCoderRunUiAutoRefreshing(phase, pauseState) ? ACTIVE_CODER_RUN_UI_REFRESH_INTERVAL_MS : undefined;
|
|
53201
|
-
}
|
|
53202
|
-
|
|
53203
53812
|
/**
|
|
53204
53813
|
* Maximum number of output lines reserved for agent output in the UI.
|
|
53205
53814
|
*/
|
|
53206
53815
|
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
53207
|
-
/**
|
|
53208
|
-
* Minimum width used for the rich coder-run frame.
|
|
53209
|
-
*/
|
|
53210
|
-
const MIN_FRAME_WIDTH = 56;
|
|
53211
|
-
/**
|
|
53212
|
-
* Maximum width used for the rich coder-run frame.
|
|
53213
|
-
*/
|
|
53214
|
-
const MAX_FRAME_WIDTH = 96;
|
|
53215
53816
|
/**
|
|
53216
53817
|
* Visible width reserved for aligned labels in the session box.
|
|
53217
53818
|
*/
|
|
53218
53819
|
const SESSION_LABEL_WIDTH = 8;
|
|
53219
|
-
/**
|
|
53220
|
-
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
53221
|
-
*/
|
|
53222
|
-
function buildCoderRunUiFrame(options) {
|
|
53223
|
-
const totalWidth = Math.max(MIN_FRAME_WIDTH, Math.min(options.terminalWidth, MAX_FRAME_WIDTH));
|
|
53224
|
-
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
53225
|
-
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
53226
|
-
const octopusAnimationFrame = isCoderRunUiAutoRefreshing(options.phase, options.pauseState)
|
|
53227
|
-
? options.animationFrame
|
|
53228
|
-
: 0;
|
|
53229
|
-
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.statusMessage);
|
|
53230
|
-
const sessionLines = buildSessionLines(options, totalWidth, pausePresentation);
|
|
53231
|
-
const currentTaskLines = options.currentPromptLabel
|
|
53232
|
-
? [
|
|
53233
|
-
`${promptStatusPrefix}${colors.bold.white(fitPlainText(options.currentPromptLabel, totalWidth - 8))}`,
|
|
53234
|
-
`Attempt ${options.currentAttempt}/${options.maxAttempts} · ${options.statusMessage}`,
|
|
53235
|
-
...options.detailLines.map((detailLine) => `• ${detailLine}`),
|
|
53236
|
-
]
|
|
53237
|
-
: [options.statusMessage, ...options.detailLines.map((detailLine) => `• ${detailLine}`)];
|
|
53238
|
-
const visibleOutputLines = buildVisibleOutputLines(options.agentOutputLines);
|
|
53239
|
-
const controls = buildControlPills(pausePresentation.pauseControl, options.pendingEnterLabel).join(' ');
|
|
53240
|
-
const frame = [
|
|
53241
|
-
...buildCoderRunOctopusVisual({ totalWidth, animationFrame: octopusAnimationFrame }),
|
|
53242
|
-
'',
|
|
53243
|
-
...renderBox('Session', sessionLines, totalWidth, colors.yellow.bold),
|
|
53244
|
-
...renderBox(options.currentPromptLabel ? 'Current task' : 'Queue', currentTaskLines, totalWidth, colors.magenta.bold),
|
|
53245
|
-
...renderBox('Live output', visibleOutputLines, totalWidth, colors.green.bold),
|
|
53246
|
-
];
|
|
53247
|
-
if (options.errors.length > 0) {
|
|
53248
|
-
frame.push(...renderBox('Errors', options.errors.map((errorLine) => `${colors.red('✗')} ${errorLine}`), totalWidth, colors.red.bold));
|
|
53249
|
-
}
|
|
53250
|
-
frame.push(...renderBox('Controls', [controls], totalWidth, colors.white.bold));
|
|
53251
|
-
return frame;
|
|
53252
|
-
}
|
|
53253
|
-
/**
|
|
53254
|
-
* Builds the structured session lines that combine state, runner, queue, and timing metadata.
|
|
53255
|
-
*/
|
|
53256
|
-
function buildSessionLines(options, totalWidth, pausePresentation) {
|
|
53257
|
-
const bodyWidth = Math.max(10, totalWidth - 4);
|
|
53258
|
-
return buildSessionRows(options, bodyWidth, pausePresentation).map((sessionRow) => buildLabeledSessionLine(sessionRow.label, sessionRow.value, bodyWidth));
|
|
53259
|
-
}
|
|
53260
|
-
/**
|
|
53261
|
-
* Builds the session rows so the renderer can keep one consistent structure without duplicating labels.
|
|
53262
|
-
*/
|
|
53263
|
-
function buildSessionRows(options, bodyWidth, pausePresentation) {
|
|
53264
|
-
const runnerParts = [options.config.agentName || 'No agent selected'];
|
|
53265
|
-
if (options.config.modelName) {
|
|
53266
|
-
runnerParts.push(options.config.modelName);
|
|
53267
|
-
}
|
|
53268
|
-
if (options.config.thinkingLevel) {
|
|
53269
|
-
runnerParts.push(`thinking ${options.config.thinkingLevel}`);
|
|
53270
|
-
}
|
|
53271
|
-
const configurationRows = [
|
|
53272
|
-
...buildOptionalSessionRow('Context', options.config.context),
|
|
53273
|
-
...buildOptionalSessionRow('Test', options.config.testCommand),
|
|
53274
|
-
];
|
|
53275
|
-
return [
|
|
53276
|
-
{
|
|
53277
|
-
label: 'State',
|
|
53278
|
-
value: `${pausePresentation.badge} ${pausePresentation.stateMessage}`,
|
|
53279
|
-
},
|
|
53280
|
-
{
|
|
53281
|
-
label: 'Runner',
|
|
53282
|
-
value: runnerParts.join(' · '),
|
|
53283
|
-
},
|
|
53284
|
-
...configurationRows,
|
|
53285
|
-
{
|
|
53286
|
-
label: 'This run',
|
|
53287
|
-
value: buildThisRunSummary(options.progress),
|
|
53288
|
-
},
|
|
53289
|
-
{
|
|
53290
|
-
label: 'Backlog',
|
|
53291
|
-
value: buildBacklogSummary(options.progress),
|
|
53292
|
-
},
|
|
53293
|
-
{
|
|
53294
|
-
label: 'Scope',
|
|
53295
|
-
value: buildScopeSummary(options.progress, options.config),
|
|
53296
|
-
},
|
|
53297
|
-
{
|
|
53298
|
-
label: 'Timing',
|
|
53299
|
-
value: buildTimingSummary(options.progress),
|
|
53300
|
-
},
|
|
53301
|
-
{
|
|
53302
|
-
label: 'Progress',
|
|
53303
|
-
value: buildProgressBar$1(options.progress.percentage, bodyWidth - SESSION_LABEL_WIDTH - 1, `${options.progress.percentage}% complete (${options.progress.sessionDone}/${options.progress.sessionTotal} done)`),
|
|
53304
|
-
},
|
|
53305
|
-
];
|
|
53306
|
-
}
|
|
53307
53820
|
/**
|
|
53308
53821
|
* Builds the fixed-height live output section so streaming updates do not keep resizing the frame.
|
|
53309
53822
|
*/
|
|
@@ -53339,50 +53852,6 @@ function buildLabeledSessionLine(label, value, bodyWidth) {
|
|
|
53339
53852
|
const formattedLabel = colors.gray(label.padEnd(SESSION_LABEL_WIDTH));
|
|
53340
53853
|
return `${formattedLabel} ${fitAnsiText(value, bodyWidth - SESSION_LABEL_WIDTH - 1)}`;
|
|
53341
53854
|
}
|
|
53342
|
-
/**
|
|
53343
|
-
* Builds zero or one structured session row for optional metadata.
|
|
53344
|
-
*/
|
|
53345
|
-
function buildOptionalSessionRow(label, value) {
|
|
53346
|
-
if (!value) {
|
|
53347
|
-
return [];
|
|
53348
|
-
}
|
|
53349
|
-
return [{ label, value }];
|
|
53350
|
-
}
|
|
53351
|
-
/**
|
|
53352
|
-
* Builds the active-session summary shown in the session box.
|
|
53353
|
-
*/
|
|
53354
|
-
function buildThisRunSummary(progress) {
|
|
53355
|
-
if (progress.sessionTotal === 0) {
|
|
53356
|
-
return 'No runnable prompts in current scope';
|
|
53357
|
-
}
|
|
53358
|
-
return `Task ${progress.currentPromptIndex}/${progress.sessionTotal} · ${progress.sessionDone} done · ${progress.sessionRemaining} left`;
|
|
53359
|
-
}
|
|
53360
|
-
/**
|
|
53361
|
-
* Builds the backlog/filter summary shown in the session box.
|
|
53362
|
-
*/
|
|
53363
|
-
function buildBacklogSummary(progress) {
|
|
53364
|
-
const parts = [`Repo ${progress.totalPrompts} total`];
|
|
53365
|
-
if (progress.skippedPrompts > 0) {
|
|
53366
|
-
parts.push(`${formatPromptCount$1(progress.skippedPrompts)} below priority`);
|
|
53367
|
-
}
|
|
53368
|
-
return parts.join(' · ');
|
|
53369
|
-
}
|
|
53370
|
-
/**
|
|
53371
|
-
* Builds the priority/write-order summary shown in the session box.
|
|
53372
|
-
*/
|
|
53373
|
-
function buildScopeSummary(progress, config) {
|
|
53374
|
-
const parts = [`Priority ≥${config.priority}`];
|
|
53375
|
-
if (progress.toBeWrittenPrompts > 0) {
|
|
53376
|
-
parts.push(`Write ${formatPromptCount$1(progress.toBeWrittenPrompts)} first`);
|
|
53377
|
-
}
|
|
53378
|
-
return parts.join(' · ');
|
|
53379
|
-
}
|
|
53380
|
-
/**
|
|
53381
|
-
* Builds the elapsed/estimate summary shown in the session box.
|
|
53382
|
-
*/
|
|
53383
|
-
function buildTimingSummary(progress) {
|
|
53384
|
-
return `Elapsed ${progress.elapsedText} · Total ${progress.estimatedTotalText} · ETA ${progress.estimatedLabel}`;
|
|
53385
|
-
}
|
|
53386
53855
|
/**
|
|
53387
53856
|
* Builds the colored phase badge shown in the session box.
|
|
53388
53857
|
*/
|
|
@@ -53407,6 +53876,28 @@ function buildPausePresentation(phase, pauseState, statusMessage) {
|
|
|
53407
53876
|
pauseControl: colors.bgYellow.black(' P ') + colors.white(' Pause'),
|
|
53408
53877
|
};
|
|
53409
53878
|
}
|
|
53879
|
+
/**
|
|
53880
|
+
* Builds the progress bar shown in the session box.
|
|
53881
|
+
*/
|
|
53882
|
+
function buildProgressBar$1(percentage, availableWidth, label) {
|
|
53883
|
+
const percentageLabel = label;
|
|
53884
|
+
const barWidth = Math.max(10, availableWidth - percentageLabel.length - 1);
|
|
53885
|
+
const filledWidth = Math.round((percentage / 100) * barWidth);
|
|
53886
|
+
const emptyWidth = Math.max(0, barWidth - filledWidth);
|
|
53887
|
+
return `${colors.green('█'.repeat(filledWidth))}${colors.blue('░'.repeat(emptyWidth))} ${percentageLabel}`;
|
|
53888
|
+
}
|
|
53889
|
+
/**
|
|
53890
|
+
* Builds the control pills shown in the footer box.
|
|
53891
|
+
*/
|
|
53892
|
+
function buildControlPills(pauseControl, pendingEnterLabel) {
|
|
53893
|
+
const pills = [];
|
|
53894
|
+
if (pendingEnterLabel) {
|
|
53895
|
+
pills.push(colors.bgWhite.black(' ENTER ') + colors.white(` ${pendingEnterLabel}`));
|
|
53896
|
+
}
|
|
53897
|
+
pills.push(pauseControl);
|
|
53898
|
+
pills.push(colors.bgRed.white(' CTRL+C ') + colors.white(' Exit'));
|
|
53899
|
+
return pills;
|
|
53900
|
+
}
|
|
53410
53901
|
/**
|
|
53411
53902
|
* Builds the active phase badge shown in the session box while the runner is not paused.
|
|
53412
53903
|
*/
|
|
@@ -53431,33 +53922,190 @@ function buildRunningPhaseBadge(phase) {
|
|
|
53431
53922
|
return colors.bgWhite.black(' READY ');
|
|
53432
53923
|
}
|
|
53433
53924
|
}
|
|
53925
|
+
|
|
53434
53926
|
/**
|
|
53435
|
-
*
|
|
53927
|
+
* Refresh cadence used only while the rich coder UI needs animated updates.
|
|
53928
|
+
*
|
|
53929
|
+
* @private internal constant of coder run UI
|
|
53436
53930
|
*/
|
|
53437
|
-
|
|
53438
|
-
|
|
53439
|
-
|
|
53440
|
-
|
|
53441
|
-
|
|
53442
|
-
|
|
53931
|
+
const ACTIVE_CODER_RUN_UI_REFRESH_INTERVAL_MS = 300;
|
|
53932
|
+
/**
|
|
53933
|
+
* Phases that still benefit from automatic refreshes because the frame can change
|
|
53934
|
+
* over time even without new runner output.
|
|
53935
|
+
*
|
|
53936
|
+
* @private internal constant of coder run UI
|
|
53937
|
+
*/
|
|
53938
|
+
const AUTO_REFRESH_PHASES = ['initializing', 'loading', 'running', 'verifying'];
|
|
53939
|
+
/**
|
|
53940
|
+
* Returns whether the rich coder UI should keep animating on its own.
|
|
53941
|
+
*
|
|
53942
|
+
* @private internal utility of coder run UI
|
|
53943
|
+
*/
|
|
53944
|
+
function isCoderRunUiAutoRefreshing(phase, pauseState) {
|
|
53945
|
+
// `PAUSING` still means the current task is winding down, so keep active
|
|
53946
|
+
// animations/timers running until the runner reaches the fully paused state.
|
|
53947
|
+
if (pauseState === 'PAUSED') {
|
|
53948
|
+
return false;
|
|
53949
|
+
}
|
|
53950
|
+
return AUTO_REFRESH_PHASES.includes(phase);
|
|
53443
53951
|
}
|
|
53444
53952
|
/**
|
|
53445
|
-
*
|
|
53953
|
+
* Returns the automatic refresh interval for the current UI state.
|
|
53954
|
+
*
|
|
53955
|
+
* Waiting, paused, and completed states return `undefined` so the rich UI stays
|
|
53956
|
+
* perfectly still until actual state changes arrive.
|
|
53957
|
+
*
|
|
53958
|
+
* @private internal utility of coder run UI
|
|
53446
53959
|
*/
|
|
53447
|
-
function
|
|
53448
|
-
return
|
|
53960
|
+
function getCoderRunUiAutoRefreshInterval(phase, pauseState) {
|
|
53961
|
+
return isCoderRunUiAutoRefreshing(phase, pauseState) ? ACTIVE_CODER_RUN_UI_REFRESH_INTERVAL_MS : undefined;
|
|
53449
53962
|
}
|
|
53963
|
+
|
|
53450
53964
|
/**
|
|
53451
|
-
*
|
|
53965
|
+
* Minimum width used for the rich coder-run frame.
|
|
53452
53966
|
*/
|
|
53453
|
-
|
|
53454
|
-
|
|
53455
|
-
|
|
53456
|
-
|
|
53967
|
+
const MIN_FRAME_WIDTH$1 = 56;
|
|
53968
|
+
/**
|
|
53969
|
+
* Maximum width used for the rich coder-run frame.
|
|
53970
|
+
*/
|
|
53971
|
+
const MAX_FRAME_WIDTH$1 = 96;
|
|
53972
|
+
/**
|
|
53973
|
+
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
53974
|
+
*/
|
|
53975
|
+
function buildCoderRunUiFrame(options) {
|
|
53976
|
+
const totalWidth = Math.max(MIN_FRAME_WIDTH$1, Math.min(options.terminalWidth, MAX_FRAME_WIDTH$1));
|
|
53977
|
+
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
53978
|
+
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
53979
|
+
const octopusAnimationFrame = isCoderRunUiAutoRefreshing(options.phase, options.pauseState)
|
|
53980
|
+
? options.animationFrame
|
|
53981
|
+
: 0;
|
|
53982
|
+
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.statusMessage);
|
|
53983
|
+
const sessionLines = buildSessionLines$1(options, totalWidth, pausePresentation);
|
|
53984
|
+
const currentTaskLines = options.currentPromptLabel
|
|
53985
|
+
? [
|
|
53986
|
+
`${promptStatusPrefix}${colors.bold.white(fitPlainText(options.currentPromptLabel, totalWidth - 8))}`,
|
|
53987
|
+
`Attempt ${options.currentAttempt}/${options.maxAttempts} · ${options.statusMessage}`,
|
|
53988
|
+
...options.detailLines.map((detailLine) => `• ${detailLine}`),
|
|
53989
|
+
]
|
|
53990
|
+
: [options.statusMessage, ...options.detailLines.map((detailLine) => `• ${detailLine}`)];
|
|
53991
|
+
const visibleOutputLines = buildVisibleOutputLines(options.agentOutputLines);
|
|
53992
|
+
const controls = buildControlPills(pausePresentation.pauseControl, options.pendingEnterLabel).join(' ');
|
|
53993
|
+
const frame = [
|
|
53994
|
+
...buildCoderRunOctopusVisual({ totalWidth, animationFrame: octopusAnimationFrame }),
|
|
53995
|
+
'',
|
|
53996
|
+
...renderBox('Session', sessionLines, totalWidth, colors.yellow.bold),
|
|
53997
|
+
...renderBox(options.currentPromptLabel ? 'Current task' : 'Queue', currentTaskLines, totalWidth, colors.magenta.bold),
|
|
53998
|
+
...renderBox('Live output', visibleOutputLines, totalWidth, colors.green.bold),
|
|
53999
|
+
];
|
|
54000
|
+
if (options.errors.length > 0) {
|
|
54001
|
+
frame.push(...renderBox('Errors', options.errors.map((errorLine) => `${colors.red('✗')} ${errorLine}`), totalWidth, colors.red.bold));
|
|
53457
54002
|
}
|
|
53458
|
-
|
|
53459
|
-
|
|
53460
|
-
|
|
54003
|
+
frame.push(...renderBox('Controls', [controls], totalWidth, colors.white.bold));
|
|
54004
|
+
return frame;
|
|
54005
|
+
}
|
|
54006
|
+
/**
|
|
54007
|
+
* Builds the structured session lines that combine state, runner, queue, and timing metadata.
|
|
54008
|
+
*/
|
|
54009
|
+
function buildSessionLines$1(options, totalWidth, pausePresentation) {
|
|
54010
|
+
const bodyWidth = Math.max(10, totalWidth - 4);
|
|
54011
|
+
return buildSessionRows(options, bodyWidth, pausePresentation).map((sessionRow) => buildLabeledSessionLine(sessionRow.label, sessionRow.value, bodyWidth));
|
|
54012
|
+
}
|
|
54013
|
+
/**
|
|
54014
|
+
* Builds the session rows so the renderer can keep one consistent structure without duplicating labels.
|
|
54015
|
+
*/
|
|
54016
|
+
function buildSessionRows(options, bodyWidth, pausePresentation) {
|
|
54017
|
+
const runnerParts = [options.config.agentName || 'No agent selected'];
|
|
54018
|
+
if (options.config.modelName) {
|
|
54019
|
+
runnerParts.push(options.config.modelName);
|
|
54020
|
+
}
|
|
54021
|
+
if (options.config.thinkingLevel) {
|
|
54022
|
+
runnerParts.push(`thinking ${options.config.thinkingLevel}`);
|
|
54023
|
+
}
|
|
54024
|
+
const configurationRows = [
|
|
54025
|
+
...buildOptionalSessionRow('Context', options.config.context),
|
|
54026
|
+
...buildOptionalSessionRow('Test', options.config.testCommand),
|
|
54027
|
+
];
|
|
54028
|
+
return [
|
|
54029
|
+
{
|
|
54030
|
+
label: 'State',
|
|
54031
|
+
value: `${pausePresentation.badge} ${pausePresentation.stateMessage}`,
|
|
54032
|
+
},
|
|
54033
|
+
{
|
|
54034
|
+
label: 'Runner',
|
|
54035
|
+
value: runnerParts.join(' · '),
|
|
54036
|
+
},
|
|
54037
|
+
...configurationRows,
|
|
54038
|
+
{
|
|
54039
|
+
label: 'This run',
|
|
54040
|
+
value: buildThisRunSummary(options.progress),
|
|
54041
|
+
},
|
|
54042
|
+
{
|
|
54043
|
+
label: 'Backlog',
|
|
54044
|
+
value: buildBacklogSummary(options.progress),
|
|
54045
|
+
},
|
|
54046
|
+
{
|
|
54047
|
+
label: 'Scope',
|
|
54048
|
+
value: buildScopeSummary(options.progress, options.config),
|
|
54049
|
+
},
|
|
54050
|
+
{
|
|
54051
|
+
label: 'Timing',
|
|
54052
|
+
value: buildTimingSummary(options.progress),
|
|
54053
|
+
},
|
|
54054
|
+
{
|
|
54055
|
+
label: 'Progress',
|
|
54056
|
+
value: buildProgressBar$1(options.progress.percentage, bodyWidth - SESSION_LABEL_WIDTH - 1, `${options.progress.percentage}% complete (${options.progress.sessionDone}/${options.progress.sessionTotal} done)`),
|
|
54057
|
+
},
|
|
54058
|
+
];
|
|
54059
|
+
}
|
|
54060
|
+
/**
|
|
54061
|
+
* Builds zero or one structured session row for optional metadata.
|
|
54062
|
+
*/
|
|
54063
|
+
function buildOptionalSessionRow(label, value) {
|
|
54064
|
+
if (!value) {
|
|
54065
|
+
return [];
|
|
54066
|
+
}
|
|
54067
|
+
return [{ label, value }];
|
|
54068
|
+
}
|
|
54069
|
+
/**
|
|
54070
|
+
* Builds the active-session summary shown in the session box.
|
|
54071
|
+
*/
|
|
54072
|
+
function buildThisRunSummary(progress) {
|
|
54073
|
+
if (progress.sessionTotal === 0) {
|
|
54074
|
+
return 'No runnable prompts in current scope';
|
|
54075
|
+
}
|
|
54076
|
+
return `Task ${progress.currentPromptIndex}/${progress.sessionTotal} · ${progress.sessionDone} done · ${progress.sessionRemaining} left`;
|
|
54077
|
+
}
|
|
54078
|
+
/**
|
|
54079
|
+
* Builds the backlog/filter summary shown in the session box.
|
|
54080
|
+
*/
|
|
54081
|
+
function buildBacklogSummary(progress) {
|
|
54082
|
+
const parts = [`Repo ${progress.totalPrompts} total`];
|
|
54083
|
+
if (progress.skippedPrompts > 0) {
|
|
54084
|
+
parts.push(`${formatPromptCount$1(progress.skippedPrompts)} below priority`);
|
|
54085
|
+
}
|
|
54086
|
+
return parts.join(' · ');
|
|
54087
|
+
}
|
|
54088
|
+
/**
|
|
54089
|
+
* Builds the priority/write-order summary shown in the session box.
|
|
54090
|
+
*/
|
|
54091
|
+
function buildScopeSummary(progress, config) {
|
|
54092
|
+
const parts = [`Priority ≥${config.priority}`];
|
|
54093
|
+
if (progress.toBeWrittenPrompts > 0) {
|
|
54094
|
+
parts.push(`Write ${formatPromptCount$1(progress.toBeWrittenPrompts)} first`);
|
|
54095
|
+
}
|
|
54096
|
+
return parts.join(' · ');
|
|
54097
|
+
}
|
|
54098
|
+
/**
|
|
54099
|
+
* Builds the elapsed/estimate summary shown in the session box.
|
|
54100
|
+
*/
|
|
54101
|
+
function buildTimingSummary(progress) {
|
|
54102
|
+
return `Elapsed ${progress.elapsedText} · Total ${progress.estimatedTotalText} · ETA ${progress.estimatedLabel}`;
|
|
54103
|
+
}
|
|
54104
|
+
/**
|
|
54105
|
+
* Formats a prompt count with singular/plural wording.
|
|
54106
|
+
*/
|
|
54107
|
+
function formatPromptCount$1(count) {
|
|
54108
|
+
return `${count} prompt${count === 1 ? '' : 's'}`;
|
|
53461
54109
|
}
|
|
53462
54110
|
|
|
53463
54111
|
/**
|
|
@@ -53600,6 +54248,7 @@ class CoderRunUiState extends EventEmitter {
|
|
|
53600
54248
|
this.currentAttempt = 1;
|
|
53601
54249
|
this.maxAttempts = 3;
|
|
53602
54250
|
this.detailLines = [];
|
|
54251
|
+
this.messagePreviewLines = [];
|
|
53603
54252
|
this.agentOutputLines = [];
|
|
53604
54253
|
this.phase = 'initializing';
|
|
53605
54254
|
this.statusMessage = 'Initializing...';
|
|
@@ -53653,6 +54302,7 @@ class CoderRunUiState extends EventEmitter {
|
|
|
53653
54302
|
setCurrentPrompt(label) {
|
|
53654
54303
|
this.currentPromptLabel = label;
|
|
53655
54304
|
this.detailLines = [];
|
|
54305
|
+
this.messagePreviewLines = [];
|
|
53656
54306
|
this.pendingEnterLabel = undefined;
|
|
53657
54307
|
this.agentOutputLines = [];
|
|
53658
54308
|
this.currentAttempt = 1;
|
|
@@ -53700,6 +54350,13 @@ class CoderRunUiState extends EventEmitter {
|
|
|
53700
54350
|
this.detailLines = detailLines.filter((detailLine) => detailLine.trim() !== '');
|
|
53701
54351
|
this.emitChange();
|
|
53702
54352
|
}
|
|
54353
|
+
/**
|
|
54354
|
+
* Replaces the exact user-message preview lines shown in agent-specific panels.
|
|
54355
|
+
*/
|
|
54356
|
+
setMessagePreviewLines(messagePreviewLines) {
|
|
54357
|
+
this.messagePreviewLines = [...messagePreviewLines];
|
|
54358
|
+
this.emitChange();
|
|
54359
|
+
}
|
|
53703
54360
|
/**
|
|
53704
54361
|
* Sets or clears the Enter-key action label shown in the controls panel.
|
|
53705
54362
|
*/
|
|
@@ -53757,8 +54414,9 @@ function getTerminalWidth() {
|
|
|
53757
54414
|
*
|
|
53758
54415
|
* @private internal entry point of coder run UI
|
|
53759
54416
|
*/
|
|
53760
|
-
function renderCoderRunUi(startTime) {
|
|
54417
|
+
function renderCoderRunUi(startTime, options = {}) {
|
|
53761
54418
|
const state = new CoderRunUiState(startTime);
|
|
54419
|
+
const buildFrameLinesFromState = options.buildFrameLines || buildCoderRunUiFrame;
|
|
53762
54420
|
if (!process.stdout.isTTY) {
|
|
53763
54421
|
return {
|
|
53764
54422
|
state,
|
|
@@ -53895,7 +54553,7 @@ function renderCoderRunUi(startTime) {
|
|
|
53895
54553
|
* Builds the current frame snapshot from the latest state.
|
|
53896
54554
|
*/
|
|
53897
54555
|
function buildFrameLines() {
|
|
53898
|
-
return
|
|
54556
|
+
return buildFrameLinesFromState({
|
|
53899
54557
|
terminalWidth: getTerminalWidth(),
|
|
53900
54558
|
animationFrame: spinnerFrame,
|
|
53901
54559
|
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
@@ -53907,6 +54565,7 @@ function renderCoderRunUi(startTime) {
|
|
|
53907
54565
|
maxAttempts: state.maxAttempts,
|
|
53908
54566
|
statusMessage: state.statusMessage,
|
|
53909
54567
|
detailLines: state.detailLines,
|
|
54568
|
+
messagePreviewLines: state.messagePreviewLines,
|
|
53910
54569
|
pendingEnterLabel: state.pendingEnterLabel,
|
|
53911
54570
|
agentOutputLines: state.agentOutputLines,
|
|
53912
54571
|
errors: state.errors,
|
|
@@ -58987,7 +59646,7 @@ function buildAgentMessagePrompt(messageRelativePath) {
|
|
|
58987
59646
|
*/
|
|
58988
59647
|
function buildAgentMessageScriptPath(projectPath, messageFile) {
|
|
58989
59648
|
const scriptFileName = `${messageFile.fileName.replace(/\.[^.]+$/u, '')}.sh`;
|
|
58990
|
-
return
|
|
59649
|
+
return resolvePromptbookTempPath(projectPath, 'scripts', 'agent-messages', scriptFileName);
|
|
58991
59650
|
}
|
|
58992
59651
|
|
|
58993
59652
|
/**
|
|
@@ -59043,6 +59702,242 @@ function isFileNotFoundError(error) {
|
|
|
59043
59702
|
(error.code === 'ENOENT' || error.code === 'ENOTDIR'));
|
|
59044
59703
|
}
|
|
59045
59704
|
|
|
59705
|
+
/**
|
|
59706
|
+
* Compact 3x5 block font used for agent-name initials in the terminal dashboard.
|
|
59707
|
+
*/
|
|
59708
|
+
const BLOCK_FONT = {
|
|
59709
|
+
A: ['███', '█ █', '███', '█ █', '█ █'],
|
|
59710
|
+
B: ['██ ', '█ █', '██ ', '█ █', '██ '],
|
|
59711
|
+
C: ['███', '█ ', '█ ', '█ ', '███'],
|
|
59712
|
+
D: ['██ ', '█ █', '█ █', '█ █', '██ '],
|
|
59713
|
+
E: ['███', '█ ', '██ ', '█ ', '███'],
|
|
59714
|
+
F: ['███', '█ ', '██ ', '█ ', '█ '],
|
|
59715
|
+
G: ['███', '█ ', '█ ██', '█ █', '████'],
|
|
59716
|
+
H: ['█ █', '█ █', '███', '█ █', '█ █'],
|
|
59717
|
+
I: ['███', ' █ ', ' █ ', ' █ ', '███'],
|
|
59718
|
+
J: ['███', ' █', ' █', '█ █', '██ '],
|
|
59719
|
+
K: ['█ █', '█ █', '██ ', '█ █', '█ █'],
|
|
59720
|
+
L: ['█ ', '█ ', '█ ', '█ ', '███'],
|
|
59721
|
+
M: ['█ █', '███', '███', '█ █', '█ █'],
|
|
59722
|
+
N: ['█ █', '███', '███', '███', '█ █'],
|
|
59723
|
+
O: ['███', '█ █', '█ █', '█ █', '███'],
|
|
59724
|
+
P: ['███', '█ █', '███', '█ ', '█ '],
|
|
59725
|
+
Q: ['███', '█ █', '█ █', '███', ' █'],
|
|
59726
|
+
R: ['███', '█ █', '███', '██ ', '█ █'],
|
|
59727
|
+
S: ['███', '█ ', '███', ' █', '███'],
|
|
59728
|
+
T: ['███', ' █ ', ' █ ', ' █ ', ' █ '],
|
|
59729
|
+
U: ['█ █', '█ █', '█ █', '█ █', '███'],
|
|
59730
|
+
V: ['█ █', '█ █', '█ █', '█ █', ' █ '],
|
|
59731
|
+
W: ['█ █', '█ █', '███', '███', '█ █'],
|
|
59732
|
+
X: ['█ █', '█ █', ' █ ', '█ █', '█ █'],
|
|
59733
|
+
Y: ['█ █', '█ █', ' █ ', ' █ ', ' █ '],
|
|
59734
|
+
Z: ['███', ' █', ' █ ', '█ ', '███'],
|
|
59735
|
+
0: ['███', '█ █', '█ █', '█ █', '███'],
|
|
59736
|
+
1: [' ██', ' █', ' █', ' █', '███'],
|
|
59737
|
+
2: ['███', ' █', '███', '█ ', '███'],
|
|
59738
|
+
3: ['███', ' █', ' ██', ' █', '███'],
|
|
59739
|
+
4: ['█ █', '█ █', '███', ' █', ' █'],
|
|
59740
|
+
5: ['███', '█ ', '███', ' █', '███'],
|
|
59741
|
+
6: ['███', '█ ', '███', '█ █', '███'],
|
|
59742
|
+
7: ['███', ' █', ' █', ' █', ' █'],
|
|
59743
|
+
8: ['███', '█ █', '███', '█ █', '███'],
|
|
59744
|
+
9: ['███', '█ █', '███', ' █', '███'],
|
|
59745
|
+
};
|
|
59746
|
+
/**
|
|
59747
|
+
* Fallback glyph used when the initials contain unsupported characters.
|
|
59748
|
+
*/
|
|
59749
|
+
const UNKNOWN_LETTER = ['███', ' █', ' ██', ' ', ' ██'];
|
|
59750
|
+
/**
|
|
59751
|
+
* Builds a compact centered initials banner for `ptbk agent run`.
|
|
59752
|
+
*/
|
|
59753
|
+
function buildAgentRunInitialsVisual(agentName, totalWidth) {
|
|
59754
|
+
const initials = extractAgentInitials(agentName);
|
|
59755
|
+
const glyphRows = Array.from({ length: 5 }, () => '');
|
|
59756
|
+
for (const initial of initials) {
|
|
59757
|
+
const glyph = BLOCK_FONT[initial] || UNKNOWN_LETTER;
|
|
59758
|
+
for (let rowIndex = 0; rowIndex < glyph.length; rowIndex++) {
|
|
59759
|
+
glyphRows[rowIndex] = `${glyphRows[rowIndex]}${glyph[rowIndex]} `;
|
|
59760
|
+
}
|
|
59761
|
+
}
|
|
59762
|
+
const trimmedGlyphRows = glyphRows.map((glyphRow) => glyphRow.trimEnd());
|
|
59763
|
+
const visualWidth = trimmedGlyphRows.reduce((maxWidth, glyphRow) => Math.max(maxWidth, visibleLength(glyphRow)), 0);
|
|
59764
|
+
return trimmedGlyphRows.map((glyphRow, rowIndex) => {
|
|
59765
|
+
const coloredRow = rowIndex === 2 ? colors.cyan.bold(glyphRow) : rowIndex === 0 ? colors.blue.bold(glyphRow) : colors.white.bold(glyphRow);
|
|
59766
|
+
return centerAnsiText(padAnsiText(coloredRow, visualWidth), totalWidth);
|
|
59767
|
+
});
|
|
59768
|
+
}
|
|
59769
|
+
/**
|
|
59770
|
+
* Extracts readable initials from the local agent title.
|
|
59771
|
+
*/
|
|
59772
|
+
function extractAgentInitials(agentName) {
|
|
59773
|
+
const normalizedAlphanumericName = agentName.replace(/[^A-Za-z0-9]/gu, '').toUpperCase();
|
|
59774
|
+
const words = agentName
|
|
59775
|
+
.trim()
|
|
59776
|
+
.split(/[^A-Za-z0-9]+/u)
|
|
59777
|
+
.filter(Boolean)
|
|
59778
|
+
.map((word) => word[0].toUpperCase());
|
|
59779
|
+
if (words.length > 1) {
|
|
59780
|
+
return words.slice(0, 3);
|
|
59781
|
+
}
|
|
59782
|
+
const fallbackLetters = normalizedAlphanumericName.slice(0, 2).split('');
|
|
59783
|
+
return fallbackLetters.length > 0 ? fallbackLetters : ['A'];
|
|
59784
|
+
}
|
|
59785
|
+
|
|
59786
|
+
/**
|
|
59787
|
+
* Minimum width used for the rich agent-run frame.
|
|
59788
|
+
*/
|
|
59789
|
+
const MIN_FRAME_WIDTH = 56;
|
|
59790
|
+
/**
|
|
59791
|
+
* Maximum width used for the rich agent-run frame.
|
|
59792
|
+
*/
|
|
59793
|
+
const MAX_FRAME_WIDTH = 96;
|
|
59794
|
+
/**
|
|
59795
|
+
* Maximum number of source-message lines shown in the dedicated preview box.
|
|
59796
|
+
*/
|
|
59797
|
+
const MAX_MESSAGE_PREVIEW_LINES = 6;
|
|
59798
|
+
/**
|
|
59799
|
+
* Builds the complete boxed terminal frame for the rich `ptbk agent run` UI.
|
|
59800
|
+
*/
|
|
59801
|
+
function buildAgentRunUiFrame(options) {
|
|
59802
|
+
const totalWidth = Math.max(MIN_FRAME_WIDTH, Math.min(options.terminalWidth, MAX_FRAME_WIDTH));
|
|
59803
|
+
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
59804
|
+
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
59805
|
+
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.statusMessage);
|
|
59806
|
+
const sessionLines = buildSessionLines(options, totalWidth, pausePresentation);
|
|
59807
|
+
const currentTaskLines = options.currentPromptLabel
|
|
59808
|
+
? [
|
|
59809
|
+
`${promptStatusPrefix}${colors.bold.white(fitPlainText(options.currentPromptLabel, totalWidth - 8))}`,
|
|
59810
|
+
`Attempt ${options.currentAttempt}/${options.maxAttempts} · ${options.statusMessage}`,
|
|
59811
|
+
...options.detailLines.map((detailLine) => `• ${detailLine}`),
|
|
59812
|
+
]
|
|
59813
|
+
: [options.statusMessage, ...options.detailLines.map((detailLine) => `• ${detailLine}`)];
|
|
59814
|
+
const userMessageLines = buildUserMessagePreviewLines(options.messagePreviewLines, totalWidth);
|
|
59815
|
+
const visibleOutputLines = buildVisibleOutputLines(options.agentOutputLines);
|
|
59816
|
+
const controls = buildControlPills(pausePresentation.pauseControl, options.pendingEnterLabel).join(' ');
|
|
59817
|
+
const frame = [
|
|
59818
|
+
...buildAgentRunInitialsVisual(options.config.localAgentName || 'Local Agent', totalWidth),
|
|
59819
|
+
'',
|
|
59820
|
+
...renderBox('Session', sessionLines, totalWidth, colors.yellow.bold),
|
|
59821
|
+
...renderBox('Current task', currentTaskLines, totalWidth, colors.magenta.bold),
|
|
59822
|
+
...renderBox('User message', userMessageLines, totalWidth, colors.cyan.bold),
|
|
59823
|
+
...renderBox('Live output', visibleOutputLines, totalWidth, colors.green.bold),
|
|
59824
|
+
];
|
|
59825
|
+
if (options.errors.length > 0) {
|
|
59826
|
+
frame.push(...renderBox('Errors', options.errors.map((errorLine) => `${colors.red('✗')} ${errorLine}`), totalWidth, colors.red.bold));
|
|
59827
|
+
}
|
|
59828
|
+
frame.push(...renderBox('Controls', [controls], totalWidth, colors.white.bold));
|
|
59829
|
+
return frame;
|
|
59830
|
+
}
|
|
59831
|
+
/**
|
|
59832
|
+
* Builds the structured session lines for the agent-specific dashboard.
|
|
59833
|
+
*/
|
|
59834
|
+
function buildSessionLines(options, totalWidth, pausePresentation) {
|
|
59835
|
+
const bodyWidth = Math.max(10, totalWidth - 4);
|
|
59836
|
+
const finishedMessages = options.progress.sessionDone;
|
|
59837
|
+
const queuedMessages = options.progress.sessionRemaining;
|
|
59838
|
+
const totalMessages = options.progress.sessionTotal;
|
|
59839
|
+
const localAgentName = options.config.localAgentName || 'Local Agent';
|
|
59840
|
+
const runnerParts = [options.config.agentName || 'No runner selected'];
|
|
59841
|
+
if (options.config.modelName) {
|
|
59842
|
+
runnerParts.push(options.config.modelName);
|
|
59843
|
+
}
|
|
59844
|
+
if (options.config.thinkingLevel) {
|
|
59845
|
+
runnerParts.push(`thinking ${options.config.thinkingLevel}`);
|
|
59846
|
+
}
|
|
59847
|
+
const sessionRows = [
|
|
59848
|
+
{
|
|
59849
|
+
label: 'State',
|
|
59850
|
+
value: `${pausePresentation.badge} ${pausePresentation.stateMessage}`,
|
|
59851
|
+
},
|
|
59852
|
+
{
|
|
59853
|
+
label: 'Agent',
|
|
59854
|
+
value: localAgentName,
|
|
59855
|
+
},
|
|
59856
|
+
{
|
|
59857
|
+
label: 'Runner',
|
|
59858
|
+
value: runnerParts.join(' · '),
|
|
59859
|
+
},
|
|
59860
|
+
{
|
|
59861
|
+
label: 'Queue',
|
|
59862
|
+
value: `${totalMessages} total · ${finishedMessages} finished · ${queuedMessages} queued`,
|
|
59863
|
+
},
|
|
59864
|
+
{
|
|
59865
|
+
label: 'Timing',
|
|
59866
|
+
value: `Elapsed ${options.progress.elapsedText} · Total ${options.progress.estimatedTotalText} · ETA ${options.progress.estimatedLabel}`,
|
|
59867
|
+
},
|
|
59868
|
+
{
|
|
59869
|
+
label: 'Progress',
|
|
59870
|
+
value: buildProgressBar$1(options.progress.percentage, bodyWidth - SESSION_LABEL_WIDTH - 1, `${options.progress.percentage}% complete (${finishedMessages}/${totalMessages || 0} finished)`),
|
|
59871
|
+
},
|
|
59872
|
+
];
|
|
59873
|
+
return sessionRows.map((sessionRow) => buildLabeledSessionLine(sessionRow.label, sessionRow.value, bodyWidth));
|
|
59874
|
+
}
|
|
59875
|
+
/**
|
|
59876
|
+
* Fits the most recent user message into a fixed-height panel while preserving line breaks.
|
|
59877
|
+
*/
|
|
59878
|
+
function buildUserMessagePreviewLines(messagePreviewLines, totalWidth) {
|
|
59879
|
+
const previewWidth = Math.max(10, totalWidth - 4);
|
|
59880
|
+
const rawLines = messagePreviewLines && messagePreviewLines.length > 0
|
|
59881
|
+
? messagePreviewLines.map((messagePreviewLine) => messagePreviewLine.replace(/\t/gu, ' '))
|
|
59882
|
+
: ['No `MESSAGE @User` content found in the queued message.'];
|
|
59883
|
+
const visibleLines = rawLines.slice(0, MAX_MESSAGE_PREVIEW_LINES).map((line) => fitPlainText(line, previewWidth));
|
|
59884
|
+
if (rawLines.length > MAX_MESSAGE_PREVIEW_LINES) {
|
|
59885
|
+
visibleLines[MAX_MESSAGE_PREVIEW_LINES - 1] = fitPlainText(`${visibleLines[MAX_MESSAGE_PREVIEW_LINES - 1]} …`, previewWidth);
|
|
59886
|
+
}
|
|
59887
|
+
while (visibleLines.length < MAX_MESSAGE_PREVIEW_LINES) {
|
|
59888
|
+
visibleLines.push('');
|
|
59889
|
+
}
|
|
59890
|
+
return visibleLines;
|
|
59891
|
+
}
|
|
59892
|
+
|
|
59893
|
+
/**
|
|
59894
|
+
* Reads the local agent title and latest queued user message for the rich agent dashboard.
|
|
59895
|
+
*/
|
|
59896
|
+
async function loadAgentRunUiMetadata(projectPath, queuedMessage) {
|
|
59897
|
+
const [localAgentName, queuedMessageContent] = await Promise.all([
|
|
59898
|
+
readLocalAgentName(projectPath),
|
|
59899
|
+
readFile(queuedMessage.absolutePath, 'utf-8'),
|
|
59900
|
+
]);
|
|
59901
|
+
return {
|
|
59902
|
+
localAgentName,
|
|
59903
|
+
latestUserMessageLines: extractLatestUserMessageLines(queuedMessageContent),
|
|
59904
|
+
};
|
|
59905
|
+
}
|
|
59906
|
+
/**
|
|
59907
|
+
* Reads the local `agent.book` title and falls back to a stable generic name when unavailable.
|
|
59908
|
+
*/
|
|
59909
|
+
async function readLocalAgentName(projectPath) {
|
|
59910
|
+
try {
|
|
59911
|
+
const agentSource = await readFile(join(projectPath, AGENT_BOOK_FILE_PATH), 'utf-8');
|
|
59912
|
+
return parseAgentSourceWithCommitments(agentSource).agentName || 'Local Agent';
|
|
59913
|
+
}
|
|
59914
|
+
catch (error) {
|
|
59915
|
+
if (error &&
|
|
59916
|
+
typeof error === 'object' &&
|
|
59917
|
+
'code' in error &&
|
|
59918
|
+
(error.code === 'ENOENT' || error.code === 'ENOTDIR')) {
|
|
59919
|
+
return 'Local Agent';
|
|
59920
|
+
}
|
|
59921
|
+
throw error;
|
|
59922
|
+
}
|
|
59923
|
+
}
|
|
59924
|
+
/**
|
|
59925
|
+
* Extracts the latest `MESSAGE @User` block while preserving the original line breaks.
|
|
59926
|
+
*/
|
|
59927
|
+
function extractLatestUserMessageLines(messageContent) {
|
|
59928
|
+
const messageBlockPattern = /^MESSAGE\s+@User\b[^\n]*\n([\s\S]*?)(?=^MESSAGE\s+@|(?![\s\S]))/gmu;
|
|
59929
|
+
let latestMatch = null;
|
|
59930
|
+
while (true) {
|
|
59931
|
+
const currentMatch = messageBlockPattern.exec(messageContent);
|
|
59932
|
+
if (!currentMatch) {
|
|
59933
|
+
break;
|
|
59934
|
+
}
|
|
59935
|
+
latestMatch = currentMatch;
|
|
59936
|
+
}
|
|
59937
|
+
const latestUserMessageContent = ((latestMatch === null || latestMatch === void 0 ? void 0 : latestMatch[1]) || messageContent).trim();
|
|
59938
|
+
return latestUserMessageContent.length > 0 ? latestUserMessageContent.split(/\r?\n/gu) : [];
|
|
59939
|
+
}
|
|
59940
|
+
|
|
59046
59941
|
/**
|
|
59047
59942
|
* Converts `ptbk agent` options into the shared runner option shape.
|
|
59048
59943
|
*/
|
|
@@ -59091,7 +59986,8 @@ function validateAgentRunOptions(options) {
|
|
|
59091
59986
|
async function tickAgentMessages(options, tickOptions = {}) {
|
|
59092
59987
|
validateAgentRunOptions(options);
|
|
59093
59988
|
const projectPath = process.cwd();
|
|
59094
|
-
let
|
|
59989
|
+
let queueSnapshot = await loadAgentMessageQueueSnapshot(projectPath);
|
|
59990
|
+
let queuedMessage = queueSnapshot.queuedMessages[0];
|
|
59095
59991
|
if (!queuedMessage) {
|
|
59096
59992
|
announceNoQueuedMessages(tickOptions);
|
|
59097
59993
|
return { isMessageProcessed: false };
|
|
@@ -59100,7 +59996,8 @@ async function tickAgentMessages(options, tickOptions = {}) {
|
|
|
59100
59996
|
await ensureCleanQueueIfNeeded(projectPath, options);
|
|
59101
59997
|
console.info(colors.gray('Pulling latest changes before answering the next message...'));
|
|
59102
59998
|
await pullLatestChanges();
|
|
59103
|
-
|
|
59999
|
+
queueSnapshot = await loadAgentMessageQueueSnapshot(projectPath);
|
|
60000
|
+
queuedMessage = queueSnapshot.queuedMessages[0];
|
|
59104
60001
|
if (!queuedMessage) {
|
|
59105
60002
|
announceNoQueuedMessages(tickOptions);
|
|
59106
60003
|
return { isMessageProcessed: false };
|
|
@@ -59109,7 +60006,8 @@ async function tickAgentMessages(options, tickOptions = {}) {
|
|
|
59109
60006
|
await ensureCleanQueueIfNeeded(projectPath, options);
|
|
59110
60007
|
const sharedRunOptions = createCoderRunOptionsForAgent(options);
|
|
59111
60008
|
const { runner, actualRunnerModel } = resolvePromptRunner(sharedRunOptions);
|
|
59112
|
-
const
|
|
60009
|
+
const agentUiMetadata = await loadAgentRunUiMetadata(projectPath, queuedMessage);
|
|
60010
|
+
const uiHandle = createAgentRunUiHandle(options, runner, actualRunnerModel, queuedMessage, queueSnapshot, agentUiMetadata);
|
|
59113
60011
|
try {
|
|
59114
60012
|
const finishedMessage = await runQueuedAgentMessage({
|
|
59115
60013
|
projectPath,
|
|
@@ -59118,6 +60016,10 @@ async function tickAgentMessages(options, tickOptions = {}) {
|
|
|
59118
60016
|
queuedMessage,
|
|
59119
60017
|
uiHandle,
|
|
59120
60018
|
});
|
|
60019
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(createAgentQueueProgressSnapshot({
|
|
60020
|
+
finishedMessageCount: queueSnapshot.finishedMessageCount + 1,
|
|
60021
|
+
queuedMessages: queueSnapshot.queuedMessages.slice(1),
|
|
60022
|
+
}));
|
|
59121
60023
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Message answered');
|
|
59122
60024
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
59123
60025
|
return {
|
|
@@ -59186,24 +60088,21 @@ async function runQueuedAgentMessage(options) {
|
|
|
59186
60088
|
/**
|
|
59187
60089
|
* Creates and seeds the rich terminal UI for an agent message run.
|
|
59188
60090
|
*/
|
|
59189
|
-
function createAgentRunUiHandle(options, runner, actualRunnerModel, queuedMessage) {
|
|
60091
|
+
function createAgentRunUiHandle(options, runner, actualRunnerModel, queuedMessage, queueSnapshot, agentUiMetadata) {
|
|
59190
60092
|
if (options.noUi || !process.stdout.isTTY) {
|
|
59191
60093
|
return undefined;
|
|
59192
60094
|
}
|
|
59193
|
-
const uiHandle = renderCoderRunUi(moment());
|
|
60095
|
+
const uiHandle = renderCoderRunUi(moment(), { buildFrameLines: buildAgentRunUiFrame });
|
|
59194
60096
|
uiHandle.state.setConfig({
|
|
59195
60097
|
agentName: runner.name,
|
|
60098
|
+
localAgentName: agentUiMetadata.localAgentName,
|
|
59196
60099
|
modelName: actualRunnerModel,
|
|
59197
60100
|
thinkingLevel: options.thinkingLevel,
|
|
59198
60101
|
priority: 0,
|
|
59199
60102
|
});
|
|
59200
|
-
uiHandle.state.updateProgress(
|
|
59201
|
-
done: 0,
|
|
59202
|
-
forAgent: 1,
|
|
59203
|
-
belowMinimumPriority: 0,
|
|
59204
|
-
toBeWritten: 0,
|
|
59205
|
-
});
|
|
60103
|
+
uiHandle.state.updateProgress(createAgentQueueProgressSnapshot(queueSnapshot));
|
|
59206
60104
|
uiHandle.state.setCurrentPrompt(queuedMessage.relativePath);
|
|
60105
|
+
uiHandle.state.setMessagePreviewLines([...agentUiMetadata.latestUserMessageLines]);
|
|
59207
60106
|
uiHandle.state.setPhase('loading');
|
|
59208
60107
|
uiHandle.state.setStatusMessage('Preparing message');
|
|
59209
60108
|
return uiHandle;
|
|
@@ -59233,11 +60132,15 @@ function buildCommitIncludePaths(queuedMessage, finishedMessage, isQueuedMessage
|
|
|
59233
60132
|
return [finishedMessage.relativePath];
|
|
59234
60133
|
}
|
|
59235
60134
|
/**
|
|
59236
|
-
*
|
|
60135
|
+
* Converts agent queue counts into the prompt-style snapshot used by the shared rich UI state.
|
|
59237
60136
|
*/
|
|
59238
|
-
|
|
59239
|
-
|
|
59240
|
-
|
|
60137
|
+
function createAgentQueueProgressSnapshot(queueSnapshot) {
|
|
60138
|
+
return {
|
|
60139
|
+
done: queueSnapshot.finishedMessageCount,
|
|
60140
|
+
forAgent: queueSnapshot.queuedMessages.length,
|
|
60141
|
+
belowMinimumPriority: 0,
|
|
60142
|
+
toBeWritten: 0,
|
|
60143
|
+
};
|
|
59241
60144
|
}
|
|
59242
60145
|
/**
|
|
59243
60146
|
* Runs the clean working tree guard unless the user explicitly disabled it.
|
|
@@ -59278,6 +60181,38 @@ function announceNoQueuedMessages(options) {
|
|
|
59278
60181
|
}
|
|
59279
60182
|
console.info(colors.gray('No queued agent messages.'));
|
|
59280
60183
|
}
|
|
60184
|
+
/**
|
|
60185
|
+
* Reads current queued and finished message counts for the agent dashboard.
|
|
60186
|
+
*/
|
|
60187
|
+
async function loadAgentMessageQueueSnapshot(projectPath) {
|
|
60188
|
+
const [queuedMessages, finishedMessageCount] = await Promise.all([
|
|
60189
|
+
listQueuedAgentMessages(projectPath),
|
|
60190
|
+
countMarkdownFiles(join(projectPath, AGENT_FINISHED_MESSAGES_DIRECTORY_PATH)),
|
|
60191
|
+
]);
|
|
60192
|
+
return {
|
|
60193
|
+
queuedMessages,
|
|
60194
|
+
finishedMessageCount,
|
|
60195
|
+
};
|
|
60196
|
+
}
|
|
60197
|
+
/**
|
|
60198
|
+
* Counts markdown files inside one queue directory and treats a missing directory as empty.
|
|
60199
|
+
*/
|
|
60200
|
+
async function countMarkdownFiles(directoryPath) {
|
|
60201
|
+
try {
|
|
60202
|
+
const directoryEntries = await readdir(directoryPath, { withFileTypes: true });
|
|
60203
|
+
return directoryEntries.filter((directoryEntry) => directoryEntry.isFile() && /\.m(?:d|arkdown)$/iu.test(directoryEntry.name))
|
|
60204
|
+
.length;
|
|
60205
|
+
}
|
|
60206
|
+
catch (error) {
|
|
60207
|
+
if (error &&
|
|
60208
|
+
typeof error === 'object' &&
|
|
60209
|
+
'code' in error &&
|
|
60210
|
+
(error.code === 'ENOENT' || error.code === 'ENOTDIR')) {
|
|
60211
|
+
return 0;
|
|
60212
|
+
}
|
|
60213
|
+
throw error;
|
|
60214
|
+
}
|
|
60215
|
+
}
|
|
59281
60216
|
|
|
59282
60217
|
var tickAgentMessages$1 = /*#__PURE__*/Object.freeze({
|
|
59283
60218
|
__proto__: null,
|
|
@@ -59406,11 +60341,11 @@ const DEFAULT_INCLUDE_GLOBS = ['**/*.{ts,tsx,js,jsx,json,md,txt}'];
|
|
|
59406
60341
|
/**
|
|
59407
60342
|
* Default ignored paths while scanning the repository.
|
|
59408
60343
|
*/
|
|
59409
|
-
const DEFAULT_IGNORE_GLOBS = ['**/node_modules/**', '**/.git/**', '
|
|
60344
|
+
const DEFAULT_IGNORE_GLOBS = ['**/node_modules/**', '**/.git/**', `**/${getPromptbookTempPosixPath('ptbk-coder')}/**`];
|
|
59410
60345
|
/**
|
|
59411
60346
|
* Directory used for Promptbook coder runtime caches.
|
|
59412
60347
|
*/
|
|
59413
|
-
const PTBK_CODER_CACHE_DIRECTORY_PATH = '
|
|
60348
|
+
const PTBK_CODER_CACHE_DIRECTORY_PATH = getPromptbookTempPath('ptbk-coder');
|
|
59414
60349
|
/**
|
|
59415
60350
|
* Relative cache file path storing per-file emoji-tag scan results.
|
|
59416
60351
|
*/
|