@promptbook/cli 0.112.0-117 → 0.112.0-119
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/apps/agents-server/src/app/agents/[agentName]/chat/AgentChatSidebarDefault.tsx +5 -6
- package/apps/agents-server/src/app/api/page-preview/check/route.ts +31 -0
- package/apps/agents-server/src/app/api/page-preview/screenshot/route.ts +57 -0
- package/apps/agents-server/src/app/api/upload/route.ts +10 -1
- package/apps/agents-server/src/app/s3/[first]/[second]/[hash]/[filename]/route.ts +52 -0
- package/apps/agents-server/src/database/$provideClientSql.ts +37 -0
- package/apps/agents-server/src/database/$provideSupabaseForServer.ts +41 -0
- package/apps/agents-server/src/tools/$provideCdnForServer.ts +24 -0
- package/apps/agents-server/src/utils/cdn/classes/DigitalOceanSpaces.ts +30 -2
- package/apps/agents-server/src/utils/cdn/utils/getUserFileCdnKey.ts +10 -3
- package/apps/agents-server/src/utils/externalChatRunner/processExternalUserChatJob.ts +17 -7
- package/apps/agents-server/src/utils/iframe/checkIfUrlCanBeEmbedded.ts +68 -0
- package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +17 -7
- package/apps/agents-server/src/utils/userChat/createImmediateUserChatAnswerModelRequirements.ts +11 -0
- package/apps/agents-server/src/utils/userChat/listUserChats.ts +5 -7
- package/esm/index.es.js +442 -66
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/parseDuration.d.ts +19 -0
- package/esm/src/_packages/node.index.d.ts +10 -0
- package/esm/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
- package/esm/src/book-3.0/CliAgent.d.ts +7 -2
- package/esm/src/book-3.0/cliAgentEnv.d.ts +33 -0
- package/esm/src/book-components/BookEditor/BookEditor.d.ts +1 -1
- package/esm/src/book-components/BookEditor/BookEditorForClient.d.ts +1 -1
- package/esm/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
- package/esm/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
- package/esm/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
- package/esm/src/book-components/_common/Modal/Modal.d.ts +1 -1
- package/esm/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/esm/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/esm/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
- package/esm/src/book-components/icons/FullscreenIcon.d.ts +1 -1
- package/esm/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/_packages/node.index.ts +10 -0
- package/src/avatars/avatarAnimationScheduler.ts +33 -2
- package/src/avatars/visuals/fractalAvatarVisual.ts +5 -4
- package/src/avatars/visuals/minecraft2AvatarVisual.ts +16 -11
- package/src/avatars/visuals/minecraftAvatarVisual.ts +21 -7
- package/src/avatars/visuals/octopus3d2AvatarVisual.ts +69 -17
- package/src/avatars/visuals/octopus3d3AvatarVisual.ts +81 -18
- package/src/avatars/visuals/octopus3dAvatarVisual.ts +69 -17
- package/src/book-3.0/Book.ts +3 -1
- package/src/book-3.0/BookNodeAgentSource.ts +2 -2
- package/src/book-3.0/CliAgent.ts +84 -6
- package/src/book-3.0/LiteAgent.ts +1 -1
- package/src/book-3.0/cliAgentEnv.ts +46 -0
- package/src/book-components/BookEditor/BookEditor.tsx +6 -6
- package/src/book-components/BookEditor/BookEditorForClient.tsx +1 -1
- package/src/book-components/Chat/Chat/Chat.module.css +45 -0
- package/src/book-components/Chat/Chat/ChatCitationModal.tsx +2 -2
- package/src/book-components/Chat/Chat/CitationIframePreview.tsx +83 -0
- package/src/book-components/_common/Dropdown/Dropdown.tsx +1 -1
- package/src/book-components/_common/MenuHoisting/MenuHoistingContext.tsx +1 -1
- package/src/book-components/_common/Modal/Modal.tsx +1 -1
- package/src/book-components/icons/AboutIcon.tsx +1 -1
- package/src/book-components/icons/DownloadIcon.tsx +1 -1
- package/src/book-components/icons/ExitFullscreenIcon.tsx +1 -1
- package/src/book-components/icons/FullscreenIcon.tsx +1 -1
- package/src/cli/cli-commands/agents-server/buildAgentsServer.ts +31 -1
- package/src/cli/cli-commands/coder/run.ts +28 -3
- package/src/cli/cli-commands/common/promptRunnerCliOptions.ts +9 -29
- package/src/execution/createPipelineExecutor/getKnowledgeForTask.ts +1 -1
- package/src/llm-providers/openai/OpenAiAgentKitExecutionToolsToolBuilder.ts +1 -1
- package/src/llm-providers/openai/OpenAiAssistantExecutionToolsToolRunner.ts +1 -1
- package/src/llm-providers/openai/OpenAiVectorStoreKnowledgeSourcePreparer.ts +1 -1
- package/src/other/templates/getTemplatesPipelineCollection.ts +734 -711
- package/src/scripting/javascript/JavascriptEvalExecutionTools.ts +1 -1
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -0
- package/umd/index.umd.js +442 -66
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/parseDuration.d.ts +19 -0
- package/umd/src/_packages/node.index.d.ts +10 -0
- package/umd/src/book-3.0/BookNodeAgentSource.d.ts +1 -1
- package/umd/src/book-3.0/CliAgent.d.ts +7 -2
- package/umd/src/book-3.0/cliAgentEnv.d.ts +33 -0
- package/umd/src/book-components/BookEditor/BookEditor.d.ts +1 -1
- package/umd/src/book-components/BookEditor/BookEditorForClient.d.ts +1 -1
- package/umd/src/book-components/Chat/Chat/CitationIframePreview.d.ts +20 -0
- package/umd/src/book-components/_common/Dropdown/Dropdown.d.ts +1 -1
- package/umd/src/book-components/_common/MenuHoisting/MenuHoistingContext.d.ts +1 -1
- package/umd/src/book-components/_common/Modal/Modal.d.ts +1 -1
- package/umd/src/book-components/icons/AboutIcon.d.ts +1 -1
- package/umd/src/book-components/icons/DownloadIcon.d.ts +1 -1
- package/umd/src/book-components/icons/ExitFullscreenIcon.d.ts +1 -1
- package/umd/src/book-components/icons/FullscreenIcon.d.ts +1 -1
- package/umd/src/cli/cli-commands/common/promptRunnerCliOptions.d.ts +2 -18
- package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js
CHANGED
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
* @generated
|
|
64
64
|
* @see https://github.com/webgptorg/promptbook
|
|
65
65
|
*/
|
|
66
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
66
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-119';
|
|
67
67
|
/**
|
|
68
68
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
69
69
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1745,12 +1745,13 @@
|
|
|
1745
1745
|
}
|
|
1746
1746
|
// Note: [🟡] Code for CLI command [run](src/cli/cli-commands/coder/run.ts) should never be published outside of `@promptbook/cli`
|
|
1747
1747
|
|
|
1748
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1748
1749
|
/**
|
|
1749
|
-
*
|
|
1750
|
+
* All CLI harness names supported by `CliAgent` and `ptbk agent exec`.
|
|
1750
1751
|
*
|
|
1751
|
-
* @
|
|
1752
|
+
* @public exported from `@promptbook/node`
|
|
1752
1753
|
*/
|
|
1753
|
-
const
|
|
1754
|
+
const CLI_AGENT_HARNESS_NAMES = [
|
|
1754
1755
|
'openai-codex',
|
|
1755
1756
|
'github-copilot',
|
|
1756
1757
|
'cline',
|
|
@@ -1759,23 +1760,33 @@
|
|
|
1759
1760
|
'gemini',
|
|
1760
1761
|
];
|
|
1761
1762
|
/**
|
|
1762
|
-
* Environment variable used as the default runner identifier when `--harness` is omitted
|
|
1763
|
+
* Environment variable used as the default runner identifier when `--harness` is omitted or not set in `CliAgent`.
|
|
1763
1764
|
*
|
|
1764
|
-
*
|
|
1765
|
+
* Set this to one of the harness names (`openai-codex`, `github-copilot`, `cline`, `claude-code`, `opencode`, `gemini`)
|
|
1766
|
+
* so that `CliAgent` and `ptbk agent exec` can run without an explicit `harness` option.
|
|
1767
|
+
*
|
|
1768
|
+
* @public exported from `@promptbook/node`
|
|
1765
1769
|
*/
|
|
1766
1770
|
const PTBK_HARNESS_ENV = 'PTBK_HARNESS';
|
|
1767
1771
|
/**
|
|
1768
|
-
* Environment variable used as the default runner model when `--model` is omitted
|
|
1772
|
+
* Environment variable used as the default runner model when `--model` is omitted or not set in `CliAgent`.
|
|
1769
1773
|
*
|
|
1770
|
-
* @
|
|
1774
|
+
* @public exported from `@promptbook/node`
|
|
1771
1775
|
*/
|
|
1772
1776
|
const PTBK_MODEL_ENV = 'PTBK_MODEL';
|
|
1773
1777
|
/**
|
|
1774
|
-
* Environment variable used as the default
|
|
1778
|
+
* Environment variable used as the default thinking level when `--thinking-level` is omitted or not set in `CliAgent`.
|
|
1775
1779
|
*
|
|
1776
|
-
* @
|
|
1780
|
+
* @public exported from `@promptbook/node`
|
|
1777
1781
|
*/
|
|
1778
1782
|
const PTBK_THINKING_LEVEL_ENV = 'PTBK_THINKING_LEVEL';
|
|
1783
|
+
|
|
1784
|
+
/**
|
|
1785
|
+
* Runner identifiers supported by Promptbook CLI agent orchestration commands.
|
|
1786
|
+
*
|
|
1787
|
+
* @private internal utility of `promptbookCli`
|
|
1788
|
+
*/
|
|
1789
|
+
const PROMPT_RUNNER_HARNESS_NAMES = CLI_AGENT_HARNESS_NAMES;
|
|
1779
1790
|
/**
|
|
1780
1791
|
* Description block shared by runner-backed CLI commands.
|
|
1781
1792
|
*
|
|
@@ -3266,6 +3277,16 @@
|
|
|
3266
3277
|
* @private internal constant of `ptbk agents-server`
|
|
3267
3278
|
*/
|
|
3268
3279
|
const DEFAULT_AGENTS_SERVER_NEXT_DIST_DIRECTORY_NAME = '.next';
|
|
3280
|
+
/**
|
|
3281
|
+
* Node.js heap size limit (in MiB) injected into `NODE_OPTIONS` for the Next.js production build.
|
|
3282
|
+
*
|
|
3283
|
+
* Next.js webpack peaks at ~1.9 GiB on a fresh install; the Node.js default cap is ~1.7 GiB,
|
|
3284
|
+
* which causes an OOM crash on first-run VPS installations where swap is the primary resource.
|
|
3285
|
+
* Raising the limit lets the build complete on the first attempt.
|
|
3286
|
+
*
|
|
3287
|
+
* @private internal constant of `ptbk agents-server`
|
|
3288
|
+
*/
|
|
3289
|
+
const AGENTS_SERVER_BUILD_MAX_OLD_SPACE_MIB = 4096;
|
|
3269
3290
|
/**
|
|
3270
3291
|
* Environment variable passed to the bundled Next app so webpack can resolve dependencies
|
|
3271
3292
|
* installed beside `ptbk` even when the app sources are materialized into a project cache.
|
|
@@ -3663,7 +3684,10 @@
|
|
|
3663
3684
|
var _a, _b;
|
|
3664
3685
|
const buildProcess = child_process.spawn(process.execPath, [options.nextCliPath, 'build'], {
|
|
3665
3686
|
cwd: options.appPath,
|
|
3666
|
-
env:
|
|
3687
|
+
env: {
|
|
3688
|
+
...options.environment,
|
|
3689
|
+
NODE_OPTIONS: mergeNodeOptionsWithHeapSize(options.environment.NODE_OPTIONS, AGENTS_SERVER_BUILD_MAX_OLD_SPACE_MIB),
|
|
3690
|
+
},
|
|
3667
3691
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
3668
3692
|
});
|
|
3669
3693
|
(_a = buildProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (chunk) => {
|
|
@@ -3682,6 +3706,16 @@
|
|
|
3682
3706
|
});
|
|
3683
3707
|
});
|
|
3684
3708
|
}
|
|
3709
|
+
/**
|
|
3710
|
+
* Prepends `--max-old-space-size=<mib>` to `NODE_OPTIONS` unless the caller already set one.
|
|
3711
|
+
*/
|
|
3712
|
+
function mergeNodeOptionsWithHeapSize(existingNodeOptions, maxOldSpaceMib) {
|
|
3713
|
+
if (existingNodeOptions !== undefined && /--max-old-space-size[= ]/u.test(existingNodeOptions)) {
|
|
3714
|
+
return existingNodeOptions;
|
|
3715
|
+
}
|
|
3716
|
+
const heapFlag = `--max-old-space-size=${maxOldSpaceMib}`;
|
|
3717
|
+
return existingNodeOptions ? `${heapFlag} ${existingNodeOptions}` : heapFlag;
|
|
3718
|
+
}
|
|
3685
3719
|
/**
|
|
3686
3720
|
* Sends one Next build output chunk through the caller handler or to the foreground terminal.
|
|
3687
3721
|
*/
|
|
@@ -5129,6 +5163,7 @@
|
|
|
5129
5163
|
noUi: options.noUi,
|
|
5130
5164
|
thinkingLevel: options.thinkingLevel,
|
|
5131
5165
|
waitForUser: false,
|
|
5166
|
+
waitBetweenPrompts: 0,
|
|
5132
5167
|
noCommit: options.noCommit,
|
|
5133
5168
|
ignoreGitChanges: options.ignoreGitChanges,
|
|
5134
5169
|
normalizeLineEndings: options.normalizeLineEndings,
|
|
@@ -10821,21 +10856,22 @@
|
|
|
10821
10856
|
* @private helper of `fractalAvatarVisual`
|
|
10822
10857
|
*/
|
|
10823
10858
|
function drawDragonCurveLayer(context, points, options) {
|
|
10824
|
-
const {
|
|
10859
|
+
const { primaryColor, secondaryColor, tertiaryColor, shadowColor, strokeWidth, timeMs, layerIndex } = options;
|
|
10825
10860
|
const firstPoint = points[0];
|
|
10826
10861
|
const lastPoint = points[points.length - 1];
|
|
10827
10862
|
const ribbonGradient = context.createLinearGradient(firstPoint.x, firstPoint.y, lastPoint.x, lastPoint.y);
|
|
10828
10863
|
ribbonGradient.addColorStop(0, `${primaryColor}f2`);
|
|
10829
10864
|
ribbonGradient.addColorStop(0.5, `${secondaryColor}e6`);
|
|
10830
10865
|
ribbonGradient.addColorStop(1, `${tertiaryColor}f2`);
|
|
10866
|
+
// Approximate the blurred shadow stroke with a wider semi-transparent stroke instead of
|
|
10867
|
+
// context.filter blur, which triggers a costly software rasterization pass every frame.
|
|
10831
10868
|
context.save();
|
|
10832
10869
|
context.beginPath();
|
|
10833
10870
|
tracePolyline(context, points);
|
|
10834
|
-
context.strokeStyle = `${shadowColor}
|
|
10835
|
-
context.lineWidth = strokeWidth *
|
|
10871
|
+
context.strokeStyle = `${shadowColor}48`;
|
|
10872
|
+
context.lineWidth = strokeWidth * 4.5;
|
|
10836
10873
|
context.lineJoin = 'round';
|
|
10837
10874
|
context.lineCap = 'round';
|
|
10838
|
-
context.filter = `blur(${size * 0.022}px)`;
|
|
10839
10875
|
context.stroke();
|
|
10840
10876
|
context.restore();
|
|
10841
10877
|
context.beginPath();
|
|
@@ -11419,11 +11455,23 @@
|
|
|
11419
11455
|
* @private helper of `minecraft2AvatarVisual`
|
|
11420
11456
|
*/
|
|
11421
11457
|
function drawMinecraftShadow(context, size, palette, interaction, timeMs) {
|
|
11458
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.03;
|
|
11459
|
+
const cy = size * 0.85 + Math.sin(timeMs / 880) * size * 0.01;
|
|
11460
|
+
const rx = size * (0.16 + interaction.intensity * 0.015);
|
|
11461
|
+
const ry = size * 0.055;
|
|
11462
|
+
// Radial gradient approximates the blurry ellipse shadow without context.filter blur.
|
|
11422
11463
|
context.save();
|
|
11423
|
-
context.
|
|
11424
|
-
context.
|
|
11464
|
+
context.translate(cx, cy);
|
|
11465
|
+
context.scale(1, ry / rx);
|
|
11466
|
+
const blurRadius = rx * 1.4;
|
|
11467
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
11468
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
11469
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
11470
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
11471
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
11472
|
+
context.fillStyle = shadowGradient;
|
|
11425
11473
|
context.beginPath();
|
|
11426
|
-
context.
|
|
11474
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
11427
11475
|
context.fill();
|
|
11428
11476
|
context.restore();
|
|
11429
11477
|
}
|
|
@@ -11647,13 +11695,27 @@
|
|
|
11647
11695
|
spotlight.addColorStop(1, `${palette.highlight}00`);
|
|
11648
11696
|
context.fillStyle = spotlight;
|
|
11649
11697
|
context.fillRect(0, 0, size, size);
|
|
11650
|
-
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
|
|
11655
|
-
|
|
11656
|
-
|
|
11698
|
+
{
|
|
11699
|
+
// Radial gradient approximates the blurry ellipse shadow without context.filter blur.
|
|
11700
|
+
const cx = size * 0.5;
|
|
11701
|
+
const cy = size * 0.86;
|
|
11702
|
+
const rx = size * 0.2;
|
|
11703
|
+
const ry = size * 0.06;
|
|
11704
|
+
const blurRadius = rx * 1.4;
|
|
11705
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
11706
|
+
shadowGradient.addColorStop(0, 'rgba(0,0,0,0.28)');
|
|
11707
|
+
shadowGradient.addColorStop(0.45, 'rgba(0,0,0,0.14)');
|
|
11708
|
+
shadowGradient.addColorStop(0.8, 'rgba(0,0,0,0.05)');
|
|
11709
|
+
shadowGradient.addColorStop(1, 'rgba(0,0,0,0)');
|
|
11710
|
+
context.save();
|
|
11711
|
+
context.translate(cx, cy);
|
|
11712
|
+
context.scale(1, ry / rx);
|
|
11713
|
+
context.fillStyle = shadowGradient;
|
|
11714
|
+
context.beginPath();
|
|
11715
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
11716
|
+
context.fill();
|
|
11717
|
+
context.restore();
|
|
11718
|
+
}
|
|
11657
11719
|
drawVoxelCuboid(context, {
|
|
11658
11720
|
x: bodyX,
|
|
11659
11721
|
y: bodyY,
|
|
@@ -12705,6 +12767,35 @@
|
|
|
12705
12767
|
y: -0.62,
|
|
12706
12768
|
z: 0.94,
|
|
12707
12769
|
});
|
|
12770
|
+
/**
|
|
12771
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
12772
|
+
*
|
|
12773
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
12774
|
+
*/
|
|
12775
|
+
const octopus3dStableStateCache = new WeakMap();
|
|
12776
|
+
/**
|
|
12777
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
12778
|
+
*
|
|
12779
|
+
* @private helper of `octopus3dAvatarVisual`
|
|
12780
|
+
*/
|
|
12781
|
+
function getOctopus3dStableState(createRandom) {
|
|
12782
|
+
const cached = octopus3dStableStateCache.get(createRandom);
|
|
12783
|
+
if (cached !== undefined) {
|
|
12784
|
+
return cached;
|
|
12785
|
+
}
|
|
12786
|
+
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
12787
|
+
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
12788
|
+
const leftEyePhaseOffset = eyeRandom() * 0.6;
|
|
12789
|
+
const rightEyePhaseOffset = eyeRandom() * 0.6;
|
|
12790
|
+
const state = {
|
|
12791
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
12792
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
12793
|
+
leftEyePhaseOffset,
|
|
12794
|
+
rightEyePhaseOffset,
|
|
12795
|
+
};
|
|
12796
|
+
octopus3dStableStateCache.set(createRandom, state);
|
|
12797
|
+
return state;
|
|
12798
|
+
}
|
|
12708
12799
|
/**
|
|
12709
12800
|
* Proper 3D Octopus visual built from projected organic meshes and tentacles.
|
|
12710
12801
|
*
|
|
@@ -12717,10 +12808,7 @@
|
|
|
12717
12808
|
isAnimated: true,
|
|
12718
12809
|
supportsPointerTracking: true,
|
|
12719
12810
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
12720
|
-
const morphologyProfile =
|
|
12721
|
-
const animationRandom = createRandom('octopus3d-animation-profile');
|
|
12722
|
-
const eyeRandom = createRandom('octopus3d-eye-profile');
|
|
12723
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
12811
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3dStableState(createRandom);
|
|
12724
12812
|
const sceneCenterX = size * 0.5;
|
|
12725
12813
|
const sceneCenterY = size * 0.56;
|
|
12726
12814
|
const bob = Math.sin(timeMs / 920 + animationPhase) * size * 0.014;
|
|
@@ -12817,12 +12905,12 @@
|
|
|
12817
12905
|
x: -faceEyeSpacing,
|
|
12818
12906
|
y: faceEyeYOffset,
|
|
12819
12907
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -faceEyeSpacing, faceEyeYOffset),
|
|
12820
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
12908
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
12821
12909
|
drawProjectedOrganicEye(context, {
|
|
12822
12910
|
x: faceEyeSpacing,
|
|
12823
12911
|
y: faceEyeYOffset,
|
|
12824
12912
|
z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
|
|
12825
|
-
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 +
|
|
12913
|
+
}, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
12826
12914
|
drawProjectedOrganicMouth(context, [
|
|
12827
12915
|
{
|
|
12828
12916
|
x: -mouthHalfWidth,
|
|
@@ -12866,14 +12954,28 @@
|
|
|
12866
12954
|
/**
|
|
12867
12955
|
* Draws the soft ground shadow below the octopus.
|
|
12868
12956
|
*
|
|
12957
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
12958
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
12959
|
+
*
|
|
12869
12960
|
* @private helper of `octopus3dAvatarVisual`
|
|
12870
12961
|
*/
|
|
12871
12962
|
function drawOctopus3dShadow(context, size, palette, interaction, timeMs) {
|
|
12963
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.04;
|
|
12964
|
+
const cy = size * 0.87 + Math.sin(timeMs / 920) * size * 0.008;
|
|
12965
|
+
const rx = size * (0.18 + interaction.intensity * 0.02);
|
|
12966
|
+
const ry = size * 0.06;
|
|
12872
12967
|
context.save();
|
|
12873
|
-
context.
|
|
12874
|
-
context.
|
|
12968
|
+
context.translate(cx, cy);
|
|
12969
|
+
context.scale(1, ry / rx);
|
|
12970
|
+
const blurRadius = rx * 1.4;
|
|
12971
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
12972
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
12973
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
12974
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
12975
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
12976
|
+
context.fillStyle = shadowGradient;
|
|
12875
12977
|
context.beginPath();
|
|
12876
|
-
context.
|
|
12978
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
12877
12979
|
context.fill();
|
|
12878
12980
|
context.restore();
|
|
12879
12981
|
}
|
|
@@ -13104,6 +13206,35 @@
|
|
|
13104
13206
|
y: -0.6,
|
|
13105
13207
|
z: 0.98,
|
|
13106
13208
|
});
|
|
13209
|
+
/**
|
|
13210
|
+
* Cache keyed by the `createRandom` factory reference (stable per mounted `<Avatar/>`).
|
|
13211
|
+
*
|
|
13212
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
13213
|
+
*/
|
|
13214
|
+
const octopus3d2StableStateCache = new WeakMap();
|
|
13215
|
+
/**
|
|
13216
|
+
* Returns the stable per-avatar state, computing it on first access and caching for subsequent frames.
|
|
13217
|
+
*
|
|
13218
|
+
* @private helper of `octopus3d2AvatarVisual`
|
|
13219
|
+
*/
|
|
13220
|
+
function getOctopus3d2StableState(createRandom) {
|
|
13221
|
+
const cached = octopus3d2StableStateCache.get(createRandom);
|
|
13222
|
+
if (cached !== undefined) {
|
|
13223
|
+
return cached;
|
|
13224
|
+
}
|
|
13225
|
+
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
13226
|
+
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
13227
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
13228
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
13229
|
+
const state = {
|
|
13230
|
+
morphologyProfile: createOctopus3MorphologyProfile(createRandom),
|
|
13231
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
13232
|
+
leftEyePhaseOffset,
|
|
13233
|
+
rightEyePhaseOffset,
|
|
13234
|
+
};
|
|
13235
|
+
octopus3d2StableStateCache.set(createRandom, state);
|
|
13236
|
+
return state;
|
|
13237
|
+
}
|
|
13107
13238
|
/**
|
|
13108
13239
|
* Octopus 3D 2 avatar visual.
|
|
13109
13240
|
*
|
|
@@ -13116,10 +13247,7 @@
|
|
|
13116
13247
|
isAnimated: true,
|
|
13117
13248
|
supportsPointerTracking: true,
|
|
13118
13249
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
13119
|
-
const morphologyProfile =
|
|
13120
|
-
const animationRandom = createRandom('octopus3d2-animation-profile');
|
|
13121
|
-
const eyeRandom = createRandom('octopus3d2-eye-profile');
|
|
13122
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
13250
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset } = getOctopus3d2StableState(createRandom);
|
|
13123
13251
|
const sceneCenterX = size * 0.5;
|
|
13124
13252
|
const sceneCenterY = size * 0.575;
|
|
13125
13253
|
const bob = Math.sin(timeMs / 940 + animationPhase) * size * 0.013;
|
|
@@ -13172,8 +13300,8 @@
|
|
|
13172
13300
|
const rightEyeLocalCenter = sampleBlobbyOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude);
|
|
13173
13301
|
const eyeRadiusX = size * morphologyProfile.face.eyeRadiusXRatio * 0.78;
|
|
13174
13302
|
const eyeRadiusY = eyeRadiusX * morphologyProfile.face.eyeHeightRatio * 0.92;
|
|
13175
|
-
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
13176
|
-
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 +
|
|
13303
|
+
drawProjectedOrganicEye(context, leftEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
13304
|
+
drawProjectedOrganicEye(context, rightEyeLocalCenter, eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.9 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
13177
13305
|
drawProjectedOrganicMouth(context, [
|
|
13178
13306
|
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
13179
13307
|
sampleBlobbyOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
@@ -13202,14 +13330,28 @@
|
|
|
13202
13330
|
/**
|
|
13203
13331
|
* Draws the soft floor shadow that anchors the single mesh in the frame.
|
|
13204
13332
|
*
|
|
13333
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
13334
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
13335
|
+
*
|
|
13205
13336
|
* @private helper of `octopus3d2AvatarVisual`
|
|
13206
13337
|
*/
|
|
13207
13338
|
function drawBlobbyOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
13339
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.045;
|
|
13340
|
+
const cy = size * 0.88 + Math.sin(timeMs / 940) * size * 0.008;
|
|
13341
|
+
const rx = size * (0.18 + (morphologyProfile.body.horizontalStretch - 1) * 0.04 + interaction.intensity * 0.018);
|
|
13342
|
+
const ry = size * 0.062;
|
|
13208
13343
|
context.save();
|
|
13209
|
-
context.
|
|
13210
|
-
context.
|
|
13344
|
+
context.translate(cx, cy);
|
|
13345
|
+
context.scale(1, ry / rx);
|
|
13346
|
+
const blurRadius = rx * 1.4;
|
|
13347
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
13348
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
13349
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
13350
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
13351
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
13352
|
+
context.fillStyle = shadowGradient;
|
|
13211
13353
|
context.beginPath();
|
|
13212
|
-
context.
|
|
13354
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
13213
13355
|
context.fill();
|
|
13214
13356
|
context.restore();
|
|
13215
13357
|
}
|
|
@@ -13365,6 +13507,40 @@
|
|
|
13365
13507
|
* @private helper of `octopus3d3AvatarVisual`
|
|
13366
13508
|
*/
|
|
13367
13509
|
const OCTOPUS_TENTACLE_COUNT = 8;
|
|
13510
|
+
/**
|
|
13511
|
+
* Cache keyed by the `createRandom` factory reference, which is stable for the lifetime of one
|
|
13512
|
+
* mounted `<Avatar/>` component (created inside `resolveAvatarRenderDefinition` and held in a
|
|
13513
|
+
* React `useMemo`). Using a `WeakMap` ensures the entry is collected when the component unmounts.
|
|
13514
|
+
*
|
|
13515
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13516
|
+
*/
|
|
13517
|
+
const stableStateCache = new WeakMap();
|
|
13518
|
+
/**
|
|
13519
|
+
* Returns the stable per-avatar state, computing it on first access and returning the cached
|
|
13520
|
+
* result on every subsequent call within the same `<Avatar/>` mount.
|
|
13521
|
+
*
|
|
13522
|
+
* @private helper of `octopus3d3AvatarVisual`
|
|
13523
|
+
*/
|
|
13524
|
+
function getOctopus3d3StableState(createRandom) {
|
|
13525
|
+
const cached = stableStateCache.get(createRandom);
|
|
13526
|
+
if (cached !== undefined) {
|
|
13527
|
+
return cached;
|
|
13528
|
+
}
|
|
13529
|
+
const morphologyProfile = createOctopus3MorphologyProfile(createRandom);
|
|
13530
|
+
const animationRandom = createRandom('octopus3d3-animation-profile');
|
|
13531
|
+
const eyeRandom = createRandom('octopus3d3-eye-profile');
|
|
13532
|
+
const leftEyePhaseOffset = eyeRandom() * 0.7;
|
|
13533
|
+
const rightEyePhaseOffset = eyeRandom() * 0.7;
|
|
13534
|
+
const state = {
|
|
13535
|
+
morphologyProfile,
|
|
13536
|
+
animationPhase: animationRandom() * Math.PI * 2,
|
|
13537
|
+
leftEyePhaseOffset,
|
|
13538
|
+
rightEyePhaseOffset,
|
|
13539
|
+
tentacleProfiles: createContinuousTentacleProfiles(createRandom, morphologyProfile),
|
|
13540
|
+
};
|
|
13541
|
+
stableStateCache.set(createRandom, state);
|
|
13542
|
+
return state;
|
|
13543
|
+
}
|
|
13368
13544
|
/**
|
|
13369
13545
|
* Octopus 3D 3 avatar visual.
|
|
13370
13546
|
*
|
|
@@ -13377,11 +13553,7 @@
|
|
|
13377
13553
|
isAnimated: true,
|
|
13378
13554
|
supportsPointerTracking: true,
|
|
13379
13555
|
render({ context, size, palette, createRandom, timeMs, interaction }) {
|
|
13380
|
-
const morphologyProfile =
|
|
13381
|
-
const animationRandom = createRandom('octopus3d3-animation-profile');
|
|
13382
|
-
const eyeRandom = createRandom('octopus3d3-eye-profile');
|
|
13383
|
-
const animationPhase = animationRandom() * Math.PI * 2;
|
|
13384
|
-
const tentacleProfiles = createContinuousTentacleProfiles(createRandom, morphologyProfile);
|
|
13556
|
+
const { morphologyProfile, animationPhase, leftEyePhaseOffset, rightEyePhaseOffset, tentacleProfiles } = getOctopus3d3StableState(createRandom);
|
|
13385
13557
|
const sceneCenterX = size * 0.5;
|
|
13386
13558
|
const sceneCenterY = size * 0.535;
|
|
13387
13559
|
const bob = Math.sin(timeMs / 960 + animationPhase) * size * 0.012;
|
|
@@ -13458,8 +13630,8 @@
|
|
|
13458
13630
|
size,
|
|
13459
13631
|
palette,
|
|
13460
13632
|
});
|
|
13461
|
-
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase +
|
|
13462
|
-
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 +
|
|
13633
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, -eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + leftEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
13634
|
+
drawProjectedOrganicEye(context, sampleContinuousOctopusSurfacePoint(surfaceOptions, eyeLatitude, eyeLongitude), eyeRadiusX, eyeRadiusY, meshCenter, rotationX, rotationY, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.85 + rightEyePhaseOffset, interaction, morphologyProfile.face.eyeStyle);
|
|
13463
13635
|
drawProjectedOrganicMouth(context, [
|
|
13464
13636
|
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthLatitude, mouthCenterLongitude - mouthHalfLongitude),
|
|
13465
13637
|
sampleContinuousOctopusSurfacePoint(surfaceOptions, mouthCurveLatitude, mouthCenterLongitude),
|
|
@@ -13510,14 +13682,30 @@
|
|
|
13510
13682
|
/**
|
|
13511
13683
|
* Draws the soft lower shadow that anchors the octopus in the avatar frame.
|
|
13512
13684
|
*
|
|
13685
|
+
* Uses a scaled radial gradient instead of `context.filter = 'blur()'` to approximate the
|
|
13686
|
+
* blurry ellipse without triggering a costly software rasterization pass on every frame.
|
|
13687
|
+
*
|
|
13513
13688
|
* @private helper of `octopus3d3AvatarVisual`
|
|
13514
13689
|
*/
|
|
13515
13690
|
function drawContinuousOctopusShadow(context, size, palette, interaction, timeMs, morphologyProfile) {
|
|
13691
|
+
const cx = size * 0.5 + interaction.gazeX * size * 0.045;
|
|
13692
|
+
const cy = size * 0.9 + Math.sin(timeMs / 980) * size * 0.007;
|
|
13693
|
+
const rx = size * (0.19 + morphologyProfile.tentacles.rootSpreadScale * 0.022 + interaction.intensity * 0.02);
|
|
13694
|
+
const ry = size * 0.06;
|
|
13695
|
+
// Scale the context so that drawing a circle produces the correct ellipse aspect ratio,
|
|
13696
|
+
// then fill with a radial gradient that approximates the blurry edge without context.filter.
|
|
13516
13697
|
context.save();
|
|
13517
|
-
context.
|
|
13518
|
-
context.
|
|
13698
|
+
context.translate(cx, cy);
|
|
13699
|
+
context.scale(1, ry / rx);
|
|
13700
|
+
const blurRadius = rx * 1.4;
|
|
13701
|
+
const shadowGradient = context.createRadialGradient(0, 0, 0, 0, 0, blurRadius);
|
|
13702
|
+
shadowGradient.addColorStop(0, `${palette.shadow}7a`);
|
|
13703
|
+
shadowGradient.addColorStop(0.45, `${palette.shadow}44`);
|
|
13704
|
+
shadowGradient.addColorStop(0.8, `${palette.shadow}1a`);
|
|
13705
|
+
shadowGradient.addColorStop(1, `${palette.shadow}00`);
|
|
13706
|
+
context.fillStyle = shadowGradient;
|
|
13519
13707
|
context.beginPath();
|
|
13520
|
-
context.
|
|
13708
|
+
context.arc(0, 0, blurRadius, 0, Math.PI * 2);
|
|
13521
13709
|
context.fill();
|
|
13522
13710
|
context.restore();
|
|
13523
13711
|
}
|
|
@@ -28742,14 +28930,50 @@
|
|
|
28742
28930
|
* Builds the prompt sent to the selected coding runner for one queued user-thread book.
|
|
28743
28931
|
*/
|
|
28744
28932
|
function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage) {
|
|
28745
|
-
|
|
28746
|
-
|
|
28933
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
28934
|
+
# Answer 1 user question
|
|
28747
28935
|
|
|
28748
|
-
|
|
28749
|
-
|
|
28750
|
-
|
|
28751
|
-
|
|
28752
|
-
|
|
28936
|
+
- Read \`${messageRelativePath}\` and answer the most recent \`MESSAGE @User\`
|
|
28937
|
+
- Only change the queued message file by appending one new \`MESSAGE @Agent\` block
|
|
28938
|
+
- Do not modify any other file in the repository
|
|
28939
|
+
|
|
28940
|
+
## Rules for the answering
|
|
28941
|
+
|
|
28942
|
+
## Formatting
|
|
28943
|
+
|
|
28944
|
+
- You can use Markdown formatting in the messages like **bold** or *italic*
|
|
28945
|
+
|
|
28946
|
+
## Sources and citations
|
|
28947
|
+
|
|
28948
|
+
Mark sources and citations like this "【https://example.com/document123.pdf 】"
|
|
28949
|
+
|
|
28950
|
+
At the same time, you can write sources naturally in the text of the answers
|
|
28951
|
+
|
|
28952
|
+
For example:
|
|
28953
|
+
|
|
28954
|
+
> According to paragraph §745b, the fee can be waived for a person over 65 years old. 【https://praha13.cz/2026/paragraph-745.doc】
|
|
28955
|
+
|
|
28956
|
+
- "paragraph §745b" fits naturally in the text.
|
|
28957
|
+
- "【https://praha13.cz/2026/paragraph-745.doc】" The exact format of the quote is important for further processing of the answer.
|
|
28958
|
+
- The "【" and "】" symbols are used to mark the source and will be parsed, inside should be valid URL used as a source for the answer.
|
|
28959
|
+
|
|
28960
|
+
## Quick buttons
|
|
28961
|
+
|
|
28962
|
+
If there is a meaningful follow-up procedure, use quick buttons at the end of the answer:
|
|
28963
|
+
|
|
28964
|
+
\`\`\`
|
|
28965
|
+
How big is the contract you are posting?
|
|
28966
|
+
|
|
28967
|
+
[Up to 50,000 CZK](?message=We are posting an order up to 50,000 CZK)
|
|
28968
|
+
[Up to 100,000 CZK](?message=We are posting an order up to 100,000 CZK)
|
|
28969
|
+
[Over 100,000 CZK](?message=We are posting an order over 100,000 CZK)
|
|
28970
|
+
\`\`\`
|
|
28971
|
+
|
|
28972
|
+
|
|
28973
|
+
## This is how you should behave
|
|
28974
|
+
|
|
28975
|
+
${block(agentSystemMessage)}
|
|
28976
|
+
`);
|
|
28753
28977
|
}
|
|
28754
28978
|
|
|
28755
28979
|
/**
|
|
@@ -35894,7 +36118,9 @@
|
|
|
35894
36118
|
* @private internal utility of `Book`
|
|
35895
36119
|
*/
|
|
35896
36120
|
function parseCommitmentHeader(line) {
|
|
35897
|
-
|
|
36121
|
+
// Require at least 2 characters in the first keyword word to avoid treating common
|
|
36122
|
+
// single-letter words (e.g. "V" in Czech, "I" or "A" in English) as commitment headers.
|
|
36123
|
+
const match = /^([A-Z][A-Z0-9]+(?: [A-Z0-9]+)*)(?:\s+(.*))?$/u.exec(line);
|
|
35898
36124
|
if (!match) {
|
|
35899
36125
|
return null;
|
|
35900
36126
|
}
|
|
@@ -39308,6 +39534,57 @@
|
|
|
39308
39534
|
// Note: [🟡] Code for CLI command [init](src/cli/cli-commands/coder/init.ts) should never be published outside of `@promptbook/cli`
|
|
39309
39535
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
39310
39536
|
|
|
39537
|
+
/**
|
|
39538
|
+
* Pattern that matches durations like "1h", "30m", "5s", "1h30m", "1h30m5s".
|
|
39539
|
+
*/
|
|
39540
|
+
const DURATION_PATTERN = /^(?:(\d+)h)?(?:(\d+)m(?:in)?)?(?:(\d+)s)?$/;
|
|
39541
|
+
/**
|
|
39542
|
+
* Parses a human-readable duration string into milliseconds.
|
|
39543
|
+
*
|
|
39544
|
+
* Supported formats: `Xh`, `Xm`, `Xs`, and combinations like `1h30m`, `1h30m5s`.
|
|
39545
|
+
*
|
|
39546
|
+
* @returns Duration in milliseconds
|
|
39547
|
+
* @throws When the string does not match any supported format
|
|
39548
|
+
*
|
|
39549
|
+
* @private internal utility of `ptbk coder run`
|
|
39550
|
+
*/
|
|
39551
|
+
function parseDuration(durationString) {
|
|
39552
|
+
var _a, _b, _c;
|
|
39553
|
+
const trimmed = durationString.trim();
|
|
39554
|
+
if (!trimmed) {
|
|
39555
|
+
throw new Error(`Invalid duration: empty string. Expected a format like "1h", "30m", "5s", or combinations like "1h30m".`);
|
|
39556
|
+
}
|
|
39557
|
+
const match = trimmed.match(DURATION_PATTERN);
|
|
39558
|
+
if (!match || (match[1] === undefined && match[2] === undefined && match[3] === undefined)) {
|
|
39559
|
+
throw new Error(`Invalid duration: "${durationString}". Expected a format like "1h", "30m", "5s", or combinations like "1h30m5s".`);
|
|
39560
|
+
}
|
|
39561
|
+
const hours = parseInt((_a = match[1]) !== null && _a !== void 0 ? _a : '0', 10);
|
|
39562
|
+
const minutes = parseInt((_b = match[2]) !== null && _b !== void 0 ? _b : '0', 10);
|
|
39563
|
+
const seconds = parseInt((_c = match[3]) !== null && _c !== void 0 ? _c : '0', 10);
|
|
39564
|
+
return (hours * 3600 + minutes * 60 + seconds) * 1000;
|
|
39565
|
+
}
|
|
39566
|
+
/**
|
|
39567
|
+
* Formats a duration in milliseconds into a compact human-readable string.
|
|
39568
|
+
*
|
|
39569
|
+
* Examples: `3600000` → `"1h"`, `90000` → `"1m 30s"`, `5000` → `"5s"`.
|
|
39570
|
+
*
|
|
39571
|
+
* @private internal utility of `ptbk coder run`
|
|
39572
|
+
*/
|
|
39573
|
+
function formatDurationMs(ms) {
|
|
39574
|
+
const totalSeconds = Math.ceil(ms / 1000);
|
|
39575
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
39576
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
39577
|
+
const seconds = totalSeconds % 60;
|
|
39578
|
+
const parts = [];
|
|
39579
|
+
if (hours > 0)
|
|
39580
|
+
parts.push(`${hours}h`);
|
|
39581
|
+
if (minutes > 0)
|
|
39582
|
+
parts.push(`${minutes}m`);
|
|
39583
|
+
if (seconds > 0 || parts.length === 0)
|
|
39584
|
+
parts.push(`${seconds}s`);
|
|
39585
|
+
return parts.join(' ');
|
|
39586
|
+
}
|
|
39587
|
+
|
|
39311
39588
|
/**
|
|
39312
39589
|
* Initializes `coder run` command for Promptbook CLI utilities
|
|
39313
39590
|
*
|
|
@@ -39340,7 +39617,13 @@
|
|
|
39340
39617
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
39341
39618
|
addPromptRunnerExecutionOptions(command);
|
|
39342
39619
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption, 0);
|
|
39343
|
-
command.option('--
|
|
39620
|
+
command.option('--wait [duration]', _spaceTrim.spaceTrim(`
|
|
39621
|
+
Wait between prompt rounds.
|
|
39622
|
+
Without a value (default): waits for user confirmation before each prompt (interactive mode).
|
|
39623
|
+
With a duration like 1h, 30m, 5s: waits that long between prompts to avoid hitting rate limits of the harness.
|
|
39624
|
+
`), true);
|
|
39625
|
+
// Note: --no-wait disables the default interactive wait-for-user behaviour
|
|
39626
|
+
command.option('--no-wait', 'Skip all waiting between prompts and run non-interactively');
|
|
39344
39627
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
39345
39628
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
39346
39629
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
@@ -39349,10 +39632,23 @@
|
|
|
39349
39632
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
39350
39633
|
isAgentRequired: !dryRun,
|
|
39351
39634
|
});
|
|
39635
|
+
// [1] Parse the --wait option:
|
|
39636
|
+
// true (default or --wait without value): wait for user confirmation
|
|
39637
|
+
// false (--no-wait): no waiting at all
|
|
39638
|
+
// string (--wait 1h): wait that long between prompt rounds
|
|
39639
|
+
let waitForUser = false;
|
|
39640
|
+
let waitBetweenPrompts = 0;
|
|
39641
|
+
if (wait === true) {
|
|
39642
|
+
waitForUser = true;
|
|
39643
|
+
}
|
|
39644
|
+
else if (typeof wait === 'string' && wait !== '') {
|
|
39645
|
+
waitBetweenPrompts = parseDuration(wait);
|
|
39646
|
+
}
|
|
39352
39647
|
// Convert commander options to RunOptions format
|
|
39353
39648
|
const runOptions = {
|
|
39354
39649
|
dryRun,
|
|
39355
|
-
waitForUser
|
|
39650
|
+
waitForUser,
|
|
39651
|
+
waitBetweenPrompts,
|
|
39356
39652
|
noCommit: runnerOptions.noCommit,
|
|
39357
39653
|
ignoreGitChanges: runnerOptions.ignoreGitChanges,
|
|
39358
39654
|
agentName: runnerOptions.agentName,
|
|
@@ -58191,7 +58487,7 @@
|
|
|
58191
58487
|
return { skippedReason: 'invalid_data_url' };
|
|
58192
58488
|
}
|
|
58193
58489
|
return {
|
|
58194
|
-
file: new File([parsed.buffer], parsed.filename, {
|
|
58490
|
+
file: new File([new Uint8Array(parsed.buffer)], parsed.filename, {
|
|
58195
58491
|
type: parsed.mimeType,
|
|
58196
58492
|
}),
|
|
58197
58493
|
sizeBytes: parsed.buffer.length,
|
|
@@ -62795,6 +63091,7 @@
|
|
|
62795
63091
|
noUi: options.noUi,
|
|
62796
63092
|
thinkingLevel: options.thinkingLevel,
|
|
62797
63093
|
waitForUser: false,
|
|
63094
|
+
waitBetweenPrompts: 0,
|
|
62798
63095
|
noCommit: true,
|
|
62799
63096
|
ignoreGitChanges: true,
|
|
62800
63097
|
normalizeLineEndings: false,
|
|
@@ -68329,7 +68626,7 @@
|
|
|
68329
68626
|
/**
|
|
68330
68627
|
* CLI usage text for this script.
|
|
68331
68628
|
*/
|
|
68332
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--preserve-logs] [--no-ui] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--no-commit] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push] [--auto-pull]';
|
|
68629
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--preserve-logs] [--no-ui] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--wait [duration]] [--no-wait] [--no-commit] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push] [--auto-pull]';
|
|
68333
68630
|
/**
|
|
68334
68631
|
* Top-level flags supported by this command.
|
|
68335
68632
|
*/
|
|
@@ -68346,6 +68643,7 @@
|
|
|
68346
68643
|
'--allow-credits',
|
|
68347
68644
|
'--auto-migrate',
|
|
68348
68645
|
'--allow-destructive-auto-migrate',
|
|
68646
|
+
'--wait',
|
|
68349
68647
|
'--no-wait',
|
|
68350
68648
|
'--no-commit',
|
|
68351
68649
|
'--ignore-git-changes',
|
|
@@ -68384,6 +68682,22 @@
|
|
|
68384
68682
|
const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
|
|
68385
68683
|
const autoPush = args.includes('--auto-push');
|
|
68386
68684
|
const autoPull = args.includes('--auto-pull');
|
|
68685
|
+
// [1] Parse --wait [duration]:
|
|
68686
|
+
// absent or --no-wait: no waiting
|
|
68687
|
+
// --wait (no value): wait for user confirmation
|
|
68688
|
+
// --wait 1h: wait 1h between prompt rounds to avoid rate limits
|
|
68689
|
+
const waitOptionalValue = readOptionalOptionValue(args, '--wait');
|
|
68690
|
+
let waitForUser = false;
|
|
68691
|
+
let waitBetweenPrompts = 0;
|
|
68692
|
+
if (waitOptionalValue === null) {
|
|
68693
|
+
// --wait present without a duration value: interactive mode
|
|
68694
|
+
waitForUser = true;
|
|
68695
|
+
}
|
|
68696
|
+
else if (waitOptionalValue !== undefined) {
|
|
68697
|
+
// --wait <duration>: time-based wait between rounds
|
|
68698
|
+
waitBetweenPrompts = parseDuration(waitOptionalValue);
|
|
68699
|
+
}
|
|
68700
|
+
// --no-wait (or no flag): both waitForUser and waitBetweenPrompts remain false/0
|
|
68387
68701
|
let thinkingLevel;
|
|
68388
68702
|
if (hasTestCommandFlag && testCommand === undefined) {
|
|
68389
68703
|
exitWithUsageError('Missing value for --test. Use a shell command such as `npm run test` and quote it when it contains top-level CLI flags.');
|
|
@@ -68402,7 +68716,8 @@
|
|
|
68402
68716
|
}
|
|
68403
68717
|
return {
|
|
68404
68718
|
dryRun,
|
|
68405
|
-
waitForUser
|
|
68719
|
+
waitForUser,
|
|
68720
|
+
waitBetweenPrompts,
|
|
68406
68721
|
noCommit,
|
|
68407
68722
|
ignoreGitChanges,
|
|
68408
68723
|
normalizeLineEndings,
|
|
@@ -68421,6 +68736,23 @@
|
|
|
68421
68736
|
priority,
|
|
68422
68737
|
};
|
|
68423
68738
|
}
|
|
68739
|
+
/**
|
|
68740
|
+
* Reads an optional value for a flag that may appear with or without a following value.
|
|
68741
|
+
*
|
|
68742
|
+
* Returns `undefined` when the flag is absent, `null` when the flag is present but has no value
|
|
68743
|
+
* (the next token is another flag or the end of args), and the value string otherwise.
|
|
68744
|
+
*/
|
|
68745
|
+
function readOptionalOptionValue(args, flag) {
|
|
68746
|
+
if (!args.includes(flag)) {
|
|
68747
|
+
return undefined;
|
|
68748
|
+
}
|
|
68749
|
+
const index = args.indexOf(flag);
|
|
68750
|
+
const nextArg = args[index + 1];
|
|
68751
|
+
if (nextArg === undefined || nextArg.startsWith('-')) {
|
|
68752
|
+
return null;
|
|
68753
|
+
}
|
|
68754
|
+
return nextArg;
|
|
68755
|
+
}
|
|
68424
68756
|
/**
|
|
68425
68757
|
* Reads a value of a CLI option that follows a given flag.
|
|
68426
68758
|
*/
|
|
@@ -70876,6 +71208,7 @@
|
|
|
70876
71208
|
initializeRunUi(uiHandle, runner.name, actualRunnerModel, options);
|
|
70877
71209
|
let hasShownUpcomingTasks = false;
|
|
70878
71210
|
let hasWaitedForStart = false;
|
|
71211
|
+
let hasRunAtLeastOneRound = false;
|
|
70879
71212
|
while (just(true)) {
|
|
70880
71213
|
if (options.autoPull && !options.dryRun) {
|
|
70881
71214
|
await waitForRequestedPause({
|
|
@@ -70911,6 +71244,16 @@
|
|
|
70911
71244
|
}
|
|
70912
71245
|
const nextPrompt = promptQueueSnapshot.nextPrompt;
|
|
70913
71246
|
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
71247
|
+
// Wait between prompt rounds (skipped for the first round)
|
|
71248
|
+
if (hasRunAtLeastOneRound) {
|
|
71249
|
+
await waitBetweenPromptRoundsIfNeeded({
|
|
71250
|
+
options,
|
|
71251
|
+
isRichUiEnabled,
|
|
71252
|
+
progressDisplay,
|
|
71253
|
+
uiHandle,
|
|
71254
|
+
});
|
|
71255
|
+
}
|
|
71256
|
+
hasRunAtLeastOneRound = true;
|
|
70914
71257
|
hasWaitedForStart = await waitForPromptConfirmationIfNeeded({
|
|
70915
71258
|
options,
|
|
70916
71259
|
nextPrompt,
|
|
@@ -71146,6 +71489,39 @@
|
|
|
71146
71489
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
71147
71490
|
return true;
|
|
71148
71491
|
}
|
|
71492
|
+
/**
|
|
71493
|
+
* Countdown update interval for the between-rounds wait display.
|
|
71494
|
+
*/
|
|
71495
|
+
const WAIT_COUNTDOWN_UPDATE_INTERVAL_MS = 30000;
|
|
71496
|
+
/**
|
|
71497
|
+
* Waits the configured time between prompt rounds to avoid hitting harness rate limits.
|
|
71498
|
+
* Does nothing when `waitBetweenPrompts` is zero.
|
|
71499
|
+
*/
|
|
71500
|
+
async function waitBetweenPromptRoundsIfNeeded(options) {
|
|
71501
|
+
const { options: runOptions, isRichUiEnabled, progressDisplay, uiHandle } = options;
|
|
71502
|
+
const { waitBetweenPrompts } = runOptions;
|
|
71503
|
+
if (waitBetweenPrompts <= 0) {
|
|
71504
|
+
return;
|
|
71505
|
+
}
|
|
71506
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
71507
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
71508
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
71509
|
+
let remaining = waitBetweenPrompts;
|
|
71510
|
+
while (remaining > 0) {
|
|
71511
|
+
const statusMessage = `Waiting ${formatDurationMs(remaining)} before next prompt to avoid rate limits...`;
|
|
71512
|
+
if (!isRichUiEnabled) {
|
|
71513
|
+
console.info(colors__default["default"].gray(statusMessage));
|
|
71514
|
+
}
|
|
71515
|
+
else {
|
|
71516
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(statusMessage);
|
|
71517
|
+
}
|
|
71518
|
+
const sleepMs = Math.min(WAIT_COUNTDOWN_UPDATE_INTERVAL_MS, remaining);
|
|
71519
|
+
await new Promise((resolve) => setTimeout(resolve, sleepMs));
|
|
71520
|
+
remaining -= sleepMs;
|
|
71521
|
+
}
|
|
71522
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
71523
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
71524
|
+
}
|
|
71149
71525
|
/**
|
|
71150
71526
|
* Stops active displays and prints the git identity tip for real runs.
|
|
71151
71527
|
*/
|