@promptbook/cli 0.112.0-43 → 0.112.0-45
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 +1013 -459
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/CoderRunTimer.d.ts +31 -0
- package/esm/scripts/run-codex-prompts/common/buildCoderRunProgressSnapshot.d.ts +23 -0
- package/esm/scripts/run-codex-prompts/common/cliProgressDisplay.d.ts +13 -4
- package/esm/scripts/run-codex-prompts/common/progressFormatting.d.ts +16 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/$runGoScript.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/common/runGoScript/$runGoScriptUntilMarkerIdle.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/common/runGoScript/$runGoScriptWithOutput.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/common/runGoScript/buildScriptLogPath.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/runBashScriptWithOutput.d.ts +5 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +28 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/shouldDeleteTemporaryArtifact.d.ts +7 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/withPromptRuntimeLog.d.ts +6 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +2 -0
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +15 -20
- package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +28 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +2 -0
- package/esm/src/avatars/Avatar.d.ts +7 -0
- package/esm/src/avatars/avatarRenderingUtils.d.ts +117 -0
- package/esm/src/avatars/index.d.ts +6 -0
- package/esm/src/avatars/renderAvatarVisual.d.ts +9 -0
- package/esm/src/avatars/types/AvatarDefinition.d.ts +20 -0
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +96 -0
- package/esm/src/avatars/visuals/avatarVisualRegistry.d.ts +16 -0
- package/esm/src/avatars/visuals/minecraftAvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/octopusAvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/pixelArtAvatarVisual.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -1
- package/esm/src/book-2.0/agent-source/TeammateProfileResolver.d.ts +2 -1
- package/esm/src/commitments/PERSONA/PERSONA.d.ts +7 -0
- package/esm/src/commitments/STYLE/STYLE.d.ts +9 -2
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +1012 -458
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/CoderRunTimer.d.ts +31 -0
- package/umd/scripts/run-codex-prompts/common/buildCoderRunProgressSnapshot.d.ts +23 -0
- package/umd/scripts/run-codex-prompts/common/cliProgressDisplay.d.ts +13 -4
- package/umd/scripts/run-codex-prompts/common/progressFormatting.d.ts +16 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/$runGoScript.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/common/runGoScript/$runGoScriptUntilMarkerIdle.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/common/runGoScript/$runGoScriptWithOutput.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/common/runGoScript/buildScriptLogPath.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/runBashScriptWithOutput.d.ts +5 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +28 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/shouldDeleteTemporaryArtifact.d.ts +7 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/withPromptRuntimeLog.d.ts +6 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +2 -0
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +15 -20
- package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +28 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +2 -0
- package/umd/src/avatars/Avatar.d.ts +7 -0
- package/umd/src/avatars/avatarRenderingUtils.d.ts +117 -0
- package/umd/src/avatars/index.d.ts +6 -0
- package/umd/src/avatars/renderAvatarVisual.d.ts +9 -0
- package/umd/src/avatars/types/AvatarDefinition.d.ts +20 -0
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +96 -0
- package/umd/src/avatars/visuals/avatarVisualRegistry.d.ts +16 -0
- package/umd/src/avatars/visuals/minecraftAvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/octopusAvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/pixelArtAvatarVisual.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -1
- package/umd/src/book-2.0/agent-source/TeammateProfileResolver.d.ts +2 -1
- package/umd/src/commitments/PERSONA/PERSONA.d.ts +7 -0
- package/umd/src/commitments/STYLE/STYLE.d.ts +9 -2
- package/umd/src/version.d.ts +1 -1
package/esm/index.es.js
CHANGED
|
@@ -4,7 +4,7 @@ import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
|
4
4
|
import * as fs from 'fs';
|
|
5
5
|
import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'fs';
|
|
6
6
|
import { join, basename, dirname, isAbsolute, relative, extname, resolve } from 'path';
|
|
7
|
-
import { readFile, writeFile, stat, mkdir, access, constants, readdir, watch, unlink, rm, rename, rmdir } from 'fs/promises';
|
|
7
|
+
import { readFile, writeFile, stat, mkdir, access, constants, readdir, watch, unlink, rm, rename, rmdir, appendFile } from 'fs/promises';
|
|
8
8
|
import { forTime, forEver } from 'waitasecond';
|
|
9
9
|
import prompts from 'prompts';
|
|
10
10
|
import * as dotenv from 'dotenv';
|
|
@@ -58,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
58
58
|
* @generated
|
|
59
59
|
* @see https://github.com/webgptorg/promptbook
|
|
60
60
|
*/
|
|
61
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
61
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-45';
|
|
62
62
|
/**
|
|
63
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
64
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -3005,6 +3005,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
3005
3005
|
Features:
|
|
3006
3006
|
- Automatically stages and commits changes with agent identity
|
|
3007
3007
|
- Optional post-commit git push with explicit --auto-push opt-in
|
|
3008
|
+
- Optional --preserve-logs keeps temp prompt/log artifacts after successful rounds
|
|
3009
|
+
- Optional --no-ui keeps plain streaming console output for logging and debugging
|
|
3008
3010
|
- Supports GPG signing of commits
|
|
3009
3011
|
- Optional post-prompt verification with test-feedback retries
|
|
3010
3012
|
- Progress tracking and interactive controls
|
|
@@ -3020,6 +3022,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
3020
3022
|
`));
|
|
3021
3023
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
3022
3024
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
3025
|
+
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
3026
|
+
command.option('--no-ui', 'Disable the rich terminal UI and keep plain streaming console output for logging and debugging');
|
|
3023
3027
|
command.addOption(new Option('--thinking-level <thinking-level>', `Set reasoning effort for supported runners (${THINKING_LEVEL_VALUES.join(', ')})`).choices([...THINKING_LEVEL_VALUES]));
|
|
3024
3028
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption, 0);
|
|
3025
3029
|
command.option('--no-wait', 'Skip user prompts between processing');
|
|
@@ -3030,8 +3034,9 @@ function $initializeCoderRunCommand(program) {
|
|
|
3030
3034
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
3031
3035
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
3032
3036
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
3033
|
-
const { dryRun, agent, model, context, test, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
|
|
3037
|
+
const { dryRun, agent, model, context, test, preserveLogs, ui, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
|
|
3034
3038
|
const testCommand = normalizeCommandOptionValue(test);
|
|
3039
|
+
const noUi = !ui;
|
|
3035
3040
|
// Validate agent
|
|
3036
3041
|
let agentName = undefined;
|
|
3037
3042
|
if (agent) {
|
|
@@ -3061,6 +3066,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
3061
3066
|
model,
|
|
3062
3067
|
context,
|
|
3063
3068
|
testCommand,
|
|
3069
|
+
preserveLogs,
|
|
3070
|
+
noUi,
|
|
3064
3071
|
thinkingLevel,
|
|
3065
3072
|
priority,
|
|
3066
3073
|
normalizeLineEndings,
|
|
@@ -18384,7 +18391,7 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18384
18391
|
DELETE Casual conversational style
|
|
18385
18392
|
REMOVE All emoji usage
|
|
18386
18393
|
GOAL Provide professional business communications
|
|
18387
|
-
|
|
18394
|
+
WRITING RULES Use formal language and proper business etiquette
|
|
18388
18395
|
\`\`\`
|
|
18389
18396
|
|
|
18390
18397
|
\`\`\`book
|
|
@@ -18395,7 +18402,7 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18395
18402
|
DISCARD Technical jargon explanations
|
|
18396
18403
|
CANCEL Advanced troubleshooting procedures
|
|
18397
18404
|
GOAL Help users with simple, easy-to-follow solutions
|
|
18398
|
-
|
|
18405
|
+
WRITING RULES Use plain language that anyone can understand
|
|
18399
18406
|
\`\`\`
|
|
18400
18407
|
|
|
18401
18408
|
\`\`\`book
|
|
@@ -18412,11 +18419,11 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18412
18419
|
Concise Information Provider
|
|
18413
18420
|
|
|
18414
18421
|
PERSONA You are a helpful assistant who provides detailed explanations
|
|
18415
|
-
|
|
18422
|
+
WRITING RULES Include examples, analogies, and comprehensive context
|
|
18416
18423
|
CANCEL Detailed explanation style
|
|
18417
18424
|
DISCARD Examples and analogies
|
|
18418
18425
|
GOAL Provide brief, direct answers without unnecessary elaboration
|
|
18419
|
-
|
|
18426
|
+
WRITING RULES Be concise and to the point
|
|
18420
18427
|
\`\`\`
|
|
18421
18428
|
`);
|
|
18422
18429
|
}
|
|
@@ -18600,7 +18607,7 @@ class FormatCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18600
18607
|
PERSONA You are a data analysis expert
|
|
18601
18608
|
FORMAT Present results in structured tables
|
|
18602
18609
|
FORMAT Include confidence scores for all predictions
|
|
18603
|
-
|
|
18610
|
+
WRITING RULES Be concise and precise in explanations
|
|
18604
18611
|
\`\`\`
|
|
18605
18612
|
`);
|
|
18606
18613
|
}
|
|
@@ -18949,7 +18956,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18949
18956
|
* Short one-line description of GOAL.
|
|
18950
18957
|
*/
|
|
18951
18958
|
get description() {
|
|
18952
|
-
return 'Define
|
|
18959
|
+
return 'Define the effective agent **goal**; when multiple goals exist, only the last one stays effective.';
|
|
18953
18960
|
}
|
|
18954
18961
|
/**
|
|
18955
18962
|
* Icon for this commitment.
|
|
@@ -18964,12 +18971,14 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18964
18971
|
return spaceTrim$1(`
|
|
18965
18972
|
# ${this.type}
|
|
18966
18973
|
|
|
18967
|
-
Defines the main goal which should be achieved by the AI assistant.
|
|
18974
|
+
Defines the main goal which should be achieved by the AI assistant.
|
|
18975
|
+
There can be multiple goals in source, but after inheritance/source rewriting only the last \`GOAL\` /\`GOALS\` remains effective.
|
|
18968
18976
|
|
|
18969
18977
|
## Key aspects
|
|
18970
18978
|
|
|
18971
18979
|
- Both terms work identically and can be used interchangeably.
|
|
18972
|
-
- Later goals
|
|
18980
|
+
- Later goals overwrite earlier goals.
|
|
18981
|
+
- The public agent profile text is derived from the last goal.
|
|
18973
18982
|
- Goals provide clear direction and purpose for the agent's responses.
|
|
18974
18983
|
- Goals influence decision-making and response prioritization.
|
|
18975
18984
|
|
|
@@ -18982,9 +18991,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18982
18991
|
\`\`\`book
|
|
18983
18992
|
Customer Support Agent
|
|
18984
18993
|
|
|
18985
|
-
PERSONA You are a helpful customer support representative
|
|
18986
18994
|
GOAL Resolve customer issues quickly and efficiently
|
|
18987
|
-
GOAL Maintain high customer satisfaction scores
|
|
18988
18995
|
GOAL Always follow company policies and procedures
|
|
18989
18996
|
RULE Be polite and professional at all times
|
|
18990
18997
|
\`\`\`
|
|
@@ -18992,19 +18999,15 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18992
18999
|
\`\`\`book
|
|
18993
19000
|
Educational Assistant
|
|
18994
19001
|
|
|
18995
|
-
PERSONA You are an educational assistant specializing in mathematics
|
|
18996
19002
|
GOAL Help students understand mathematical concepts clearly
|
|
18997
|
-
GOAL Encourage critical thinking and problem-solving skills
|
|
18998
19003
|
GOAL Ensure all explanations are age-appropriate and accessible
|
|
18999
|
-
|
|
19004
|
+
WRITING RULES Use simple language and provide step-by-step explanations
|
|
19000
19005
|
\`\`\`
|
|
19001
19006
|
|
|
19002
19007
|
\`\`\`book
|
|
19003
19008
|
Safety-First Assistant
|
|
19004
19009
|
|
|
19005
|
-
PERSONA You are a general-purpose AI assistant
|
|
19006
19010
|
GOAL Be helpful and informative in all interactions
|
|
19007
|
-
GOAL Provide accurate and reliable information
|
|
19008
19011
|
GOAL Always prioritize user safety and ethical guidelines
|
|
19009
19012
|
RULE Never provide harmful or dangerous advice
|
|
19010
19013
|
\`\`\`
|
|
@@ -19412,7 +19415,7 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19412
19415
|
KNOWLEDGE Academic research requires careful citation and verification
|
|
19413
19416
|
KNOWLEDGE https://example.com/research-guidelines.pdf
|
|
19414
19417
|
ACTION Can help with literature reviews and data analysis
|
|
19415
|
-
|
|
19418
|
+
WRITING RULES Present information in clear, academic format
|
|
19416
19419
|
\`\`\`
|
|
19417
19420
|
`);
|
|
19418
19421
|
}
|
|
@@ -21163,7 +21166,7 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21163
21166
|
|
|
21164
21167
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
21165
21168
|
PERSONA You are a professional business assistant
|
|
21166
|
-
|
|
21169
|
+
WRITING RULES Maintain a formal and courteous tone
|
|
21167
21170
|
\`\`\`
|
|
21168
21171
|
|
|
21169
21172
|
\`\`\`book
|
|
@@ -21171,7 +21174,7 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21171
21174
|
|
|
21172
21175
|
META IMAGE /assets/creative-bot-avatar.png
|
|
21173
21176
|
PERSONA You are a creative and inspiring assistant
|
|
21174
|
-
|
|
21177
|
+
WRITING RULES Be enthusiastic and encouraging
|
|
21175
21178
|
ACTION Can help with brainstorming and ideation
|
|
21176
21179
|
\`\`\`
|
|
21177
21180
|
`);
|
|
@@ -21330,7 +21333,7 @@ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21330
21333
|
META LINK https://twitter.com/devhandle
|
|
21331
21334
|
PERSONA You are an experienced open source developer
|
|
21332
21335
|
ACTION Can help with code reviews and architecture decisions
|
|
21333
|
-
|
|
21336
|
+
WRITING RULES Be direct and technical in explanations
|
|
21334
21337
|
\`\`\`
|
|
21335
21338
|
`);
|
|
21336
21339
|
}
|
|
@@ -21536,7 +21539,7 @@ class ModelCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21536
21539
|
MODEL TEMPERATURE 0.8
|
|
21537
21540
|
MODEL TOP_P 0.9
|
|
21538
21541
|
MODEL MAX_TOKENS 2048
|
|
21539
|
-
|
|
21542
|
+
WRITING RULES Be imaginative and expressive
|
|
21540
21543
|
ACTION Can help with storytelling and character development
|
|
21541
21544
|
\`\`\`
|
|
21542
21545
|
|
|
@@ -21748,7 +21751,7 @@ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21748
21751
|
NOTE Uses RAG for accessing latest research papers
|
|
21749
21752
|
PERSONA You are a knowledgeable research assistant
|
|
21750
21753
|
ACTION Can help with literature reviews and citations
|
|
21751
|
-
|
|
21754
|
+
WRITING RULES Present information in academic format
|
|
21752
21755
|
\`\`\`
|
|
21753
21756
|
`);
|
|
21754
21757
|
}
|
|
@@ -21863,7 +21866,16 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21863
21866
|
* Short one-line description of PERSONA.
|
|
21864
21867
|
*/
|
|
21865
21868
|
get description() {
|
|
21866
|
-
return '
|
|
21869
|
+
return 'Deprecated legacy profile commitment. Prefer `GOAL` for agent profile text and inheritance-safe rewrites.';
|
|
21870
|
+
}
|
|
21871
|
+
/**
|
|
21872
|
+
* Optional UI/docs-only deprecation metadata.
|
|
21873
|
+
*/
|
|
21874
|
+
get deprecation() {
|
|
21875
|
+
return {
|
|
21876
|
+
message: 'Use `GOAL` for agent profile text and inheritance-safe rewrites.',
|
|
21877
|
+
replacedBy: ['GOAL'],
|
|
21878
|
+
};
|
|
21867
21879
|
}
|
|
21868
21880
|
/**
|
|
21869
21881
|
* Icon for this commitment.
|
|
@@ -21878,16 +21890,24 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21878
21890
|
return spaceTrim$1(`
|
|
21879
21891
|
# ${this.type}
|
|
21880
21892
|
|
|
21881
|
-
|
|
21893
|
+
Deprecated legacy commitment that defines who the agent is, their background, expertise, and personality traits.
|
|
21882
21894
|
|
|
21883
|
-
##
|
|
21895
|
+
## Migration
|
|
21884
21896
|
|
|
21885
|
-
-
|
|
21886
|
-
-
|
|
21887
|
-
-
|
|
21888
|
-
-
|
|
21897
|
+
- Existing \`${this.type}\` books still parse and compile.
|
|
21898
|
+
- New books should prefer \`GOAL\`.
|
|
21899
|
+
- Agent profile rendering now prefers the last \`GOAL\` and only falls back to \`${this.type}\` when no goal exists.
|
|
21900
|
+
- Runtime compilation keeps the legacy multi-\`PERSONA\` merge behavior for backward compatibility.
|
|
21889
21901
|
|
|
21890
|
-
##
|
|
21902
|
+
## Preferred replacement
|
|
21903
|
+
|
|
21904
|
+
\`\`\`book
|
|
21905
|
+
Programming Assistant
|
|
21906
|
+
|
|
21907
|
+
GOAL Help the user solve programming problems with practical TypeScript and React guidance.
|
|
21908
|
+
\`\`\`
|
|
21909
|
+
|
|
21910
|
+
## Legacy compatibility example
|
|
21891
21911
|
|
|
21892
21912
|
\`\`\`book
|
|
21893
21913
|
Programming Assistant
|
|
@@ -22025,7 +22045,7 @@ class RuleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22025
22045
|
RULE Always ask for clarification if the user's request is ambiguous
|
|
22026
22046
|
RULE Be polite and professional in all interactions
|
|
22027
22047
|
RULES Never provide medical or legal advice
|
|
22028
|
-
|
|
22048
|
+
WRITING RULES Maintain a friendly and helpful tone
|
|
22029
22049
|
\`\`\`
|
|
22030
22050
|
|
|
22031
22051
|
\`\`\`book
|
|
@@ -22294,8 +22314,8 @@ class ScenarioCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22294
22314
|
/**
|
|
22295
22315
|
* STYLE commitment definition
|
|
22296
22316
|
*
|
|
22297
|
-
*
|
|
22298
|
-
*
|
|
22317
|
+
* Deprecated legacy writing-style commitment kept for backward compatibility.
|
|
22318
|
+
* New books should prefer `WRITING RULES` for writing-only constraints.
|
|
22299
22319
|
*
|
|
22300
22320
|
* Example usage in agent source:
|
|
22301
22321
|
*
|
|
@@ -22314,7 +22334,16 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22314
22334
|
* Short one-line description of STYLE.
|
|
22315
22335
|
*/
|
|
22316
22336
|
get description() {
|
|
22317
|
-
return '
|
|
22337
|
+
return 'Deprecated legacy writing-style commitment. Prefer `WRITING RULES` for new books.';
|
|
22338
|
+
}
|
|
22339
|
+
/**
|
|
22340
|
+
* Optional UI/docs-only deprecation metadata.
|
|
22341
|
+
*/
|
|
22342
|
+
get deprecation() {
|
|
22343
|
+
return {
|
|
22344
|
+
message: 'Use `WRITING RULES` for writing-only constraints such as tone, length, formatting, or emoji usage.',
|
|
22345
|
+
replacedBy: ['WRITING RULES'],
|
|
22346
|
+
};
|
|
22318
22347
|
}
|
|
22319
22348
|
/**
|
|
22320
22349
|
* Icon for this commitment.
|
|
@@ -22329,15 +22358,34 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22329
22358
|
return spaceTrim$1(`
|
|
22330
22359
|
# ${this.type}
|
|
22331
22360
|
|
|
22332
|
-
|
|
22361
|
+
Deprecated legacy commitment for writing and presentation instructions.
|
|
22362
|
+
|
|
22363
|
+
## Migration
|
|
22364
|
+
|
|
22365
|
+
- Existing \`${this.type}\` books still parse and compile.
|
|
22366
|
+
- New books should prefer \`WRITING RULES\`.
|
|
22367
|
+
- Use \`WRITING SAMPLE\` when you want to anchor voice by example instead of stating constraints directly.
|
|
22368
|
+
- The plural alias \`STYLES\` is the same legacy commitment family.
|
|
22333
22369
|
|
|
22334
22370
|
## Key aspects
|
|
22335
22371
|
|
|
22336
|
-
-
|
|
22372
|
+
- \`${this.type}\` remains functional for backward compatibility only.
|
|
22337
22373
|
- Later style instructions can override earlier ones.
|
|
22338
22374
|
- Style affects both tone and presentation format.
|
|
22339
22375
|
|
|
22340
|
-
##
|
|
22376
|
+
## Preferred replacement
|
|
22377
|
+
|
|
22378
|
+
\`\`\`book
|
|
22379
|
+
Technical Writer
|
|
22380
|
+
|
|
22381
|
+
GOAL Help the user understand technical topics with practical, accurate guidance.
|
|
22382
|
+
WRITING RULES Write in a professional but friendly tone.
|
|
22383
|
+
WRITING RULES Use bullet points for lists.
|
|
22384
|
+
WRITING RULES Always provide code examples when explaining programming concepts.
|
|
22385
|
+
FORMAT Use markdown formatting with clear headings
|
|
22386
|
+
\`\`\`
|
|
22387
|
+
|
|
22388
|
+
## Legacy compatibility examples
|
|
22341
22389
|
|
|
22342
22390
|
\`\`\`book
|
|
22343
22391
|
Technical Writer
|
|
@@ -22652,7 +22700,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22652
22700
|
\`\`\`book
|
|
22653
22701
|
Legal Assistant
|
|
22654
22702
|
|
|
22655
|
-
|
|
22703
|
+
GOAL Get expert software-development advice from the teammate when legal discussion needs technical context.
|
|
22656
22704
|
TEAM You can talk with http://localhost:4440/agents/GMw67JN8TXxN7y to discuss the legal aspects.
|
|
22657
22705
|
\`\`\`
|
|
22658
22706
|
`);
|
|
@@ -23078,7 +23126,7 @@ class TemplateCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
23078
23126
|
|
|
23079
23127
|
PERSONA You are a helpful customer support representative
|
|
23080
23128
|
TEMPLATE Always structure your response with: 1) Acknowledgment, 2) Solution, 3) Follow-up question
|
|
23081
|
-
|
|
23129
|
+
WRITING RULES Be professional and empathetic
|
|
23082
23130
|
\`\`\`
|
|
23083
23131
|
|
|
23084
23132
|
\`\`\`book
|
|
@@ -23522,7 +23570,7 @@ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
23522
23570
|
|
|
23523
23571
|
PERSONA You are a news analyst who stays up-to-date with current events
|
|
23524
23572
|
USE BROWSER
|
|
23525
|
-
|
|
23573
|
+
WRITING RULES Present news in a balanced and objective manner
|
|
23526
23574
|
ACTION Can search for and summarize news articles
|
|
23527
23575
|
\`\`\`
|
|
23528
23576
|
|
|
@@ -41398,6 +41446,15 @@ const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS',
|
|
|
41398
41446
|
* @private internal constant of `createAgentModelRequirementsWithCommitments`
|
|
41399
41447
|
*/
|
|
41400
41448
|
const DELETE_COMMITMENT_TYPES = new Set(['DELETE', 'CANCEL', 'DISCARD', 'REMOVE']);
|
|
41449
|
+
/**
|
|
41450
|
+
* Commitments whose earlier occurrences are overwritten by the last occurrence in source order.
|
|
41451
|
+
*
|
|
41452
|
+
* @private internal constant of `createAgentModelRequirementsWithCommitments`
|
|
41453
|
+
*/
|
|
41454
|
+
const OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE = new Map([
|
|
41455
|
+
['GOAL', 'GOAL'],
|
|
41456
|
+
['GOALS', 'GOAL'],
|
|
41457
|
+
]);
|
|
41401
41458
|
/**
|
|
41402
41459
|
* Regex pattern matching markdown horizontal lines that should not be copied into the final system message.
|
|
41403
41460
|
*
|
|
@@ -41448,7 +41505,7 @@ function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
|
|
|
41448
41505
|
*/
|
|
41449
41506
|
async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
|
|
41450
41507
|
const parseResult = parseAgentSourceWithCommitments(agentSource);
|
|
41451
|
-
const filteredCommitments = filterDeletedCommitments(parseResult.commitments);
|
|
41508
|
+
const filteredCommitments = filterOverwrittenCommitments(filterDeletedCommitments(parseResult.commitments));
|
|
41452
41509
|
let requirements = createInitialAgentModelRequirements(parseResult.agentName, modelName);
|
|
41453
41510
|
requirements = await applyCommitmentsToRequirements(requirements, filteredCommitments, options);
|
|
41454
41511
|
requirements = aggregateUseCommitmentSystemMessages(requirements, filteredCommitments);
|
|
@@ -41459,6 +41516,35 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
|
|
|
41459
41516
|
requirements = await applyPendingInlineKnowledgeSources(requirements, options === null || options === void 0 ? void 0 : options.inlineKnowledgeSourceUploader);
|
|
41460
41517
|
return finalizeRequirements(requirements);
|
|
41461
41518
|
}
|
|
41519
|
+
/**
|
|
41520
|
+
* Removes earlier commitments that are overwritten by later commitments of the same semantic group.
|
|
41521
|
+
*
|
|
41522
|
+
* This currently keeps only the last `GOAL` / `GOALS` commitment so inheritance rewrites
|
|
41523
|
+
* and multi-goal sources expose one effective goal to the runtime.
|
|
41524
|
+
*
|
|
41525
|
+
* @param commitments - Parsed commitments after DELETE-like filtering.
|
|
41526
|
+
* @returns Commitments with overwritten entries removed while preserving source order.
|
|
41527
|
+
*
|
|
41528
|
+
* @private internal utility of `createAgentModelRequirementsWithCommitments`
|
|
41529
|
+
*/
|
|
41530
|
+
function filterOverwrittenCommitments(commitments) {
|
|
41531
|
+
const seenOverwriteGroups = new Set();
|
|
41532
|
+
const keptCommitments = [];
|
|
41533
|
+
for (let index = commitments.length - 1; index >= 0; index--) {
|
|
41534
|
+
const commitment = commitments[index];
|
|
41535
|
+
const overwriteGroup = OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE.get(commitment.type);
|
|
41536
|
+
if (!overwriteGroup) {
|
|
41537
|
+
keptCommitments.push(commitment);
|
|
41538
|
+
continue;
|
|
41539
|
+
}
|
|
41540
|
+
if (seenOverwriteGroups.has(overwriteGroup)) {
|
|
41541
|
+
continue;
|
|
41542
|
+
}
|
|
41543
|
+
seenOverwriteGroups.add(overwriteGroup);
|
|
41544
|
+
keptCommitments.push(commitment);
|
|
41545
|
+
}
|
|
41546
|
+
return keptCommitments.reverse();
|
|
41547
|
+
}
|
|
41462
41548
|
/**
|
|
41463
41549
|
* Creates the initial requirements object with the parsed agent name stored in metadata and an optional model override.
|
|
41464
41550
|
*
|
|
@@ -42101,7 +42187,7 @@ function createDefaultAgentName(agentSource) {
|
|
|
42101
42187
|
function parseAgentSource(agentSource) {
|
|
42102
42188
|
const parseResult = parseAgentSourceWithCommitments(agentSource);
|
|
42103
42189
|
const resolvedAgentName = parseResult.agentName || createDefaultAgentName(agentSource);
|
|
42104
|
-
const personaDescription =
|
|
42190
|
+
const personaDescription = extractAgentProfileText(parseResult.commitments);
|
|
42105
42191
|
const initialMessage = extractInitialMessage(parseResult.commitments);
|
|
42106
42192
|
const parsedProfile = extractParsedAgentProfile(parseResult.commitments);
|
|
42107
42193
|
ensureMetaFullname(parsedProfile.meta, resolvedAgentName);
|
|
@@ -42205,25 +42291,33 @@ const META_COMMITMENT_APPLIERS = {
|
|
|
42205
42291
|
*/
|
|
42206
42292
|
const LOCAL_AGENT_REFERENCE_PREFIXES = ['./', '../', '/'];
|
|
42207
42293
|
/**
|
|
42208
|
-
*
|
|
42294
|
+
* Resolves the public agent profile text from the last GOAL/GOALS commitment,
|
|
42295
|
+
* falling back to the deprecated PERSONA/PERSONAE commitments when no goal exists.
|
|
42209
42296
|
*
|
|
42210
42297
|
* @private internal utility of `parseAgentSource`
|
|
42211
42298
|
*/
|
|
42212
|
-
function
|
|
42213
|
-
let
|
|
42299
|
+
function extractAgentProfileText(commitments) {
|
|
42300
|
+
let goalDescription = '';
|
|
42301
|
+
let hasGoalDescription = false;
|
|
42302
|
+
let personaDescription = '';
|
|
42303
|
+
let hasPersonaDescription = false;
|
|
42214
42304
|
for (const commitment of commitments) {
|
|
42215
|
-
if (commitment.type
|
|
42216
|
-
|
|
42305
|
+
if (commitment.type === 'GOAL' || commitment.type === 'GOALS') {
|
|
42306
|
+
goalDescription = commitment.content;
|
|
42307
|
+
hasGoalDescription = true;
|
|
42217
42308
|
}
|
|
42218
|
-
if (
|
|
42219
|
-
personaDescription =
|
|
42309
|
+
if (commitment.type === 'PERSONA' || commitment.type === 'PERSONAE') {
|
|
42310
|
+
personaDescription = commitment.content;
|
|
42311
|
+
hasPersonaDescription = true;
|
|
42220
42312
|
}
|
|
42221
|
-
else {
|
|
42222
|
-
personaDescription += `\n\n${personaDescription}`;
|
|
42223
|
-
}
|
|
42224
|
-
personaDescription += commitment.content;
|
|
42225
42313
|
}
|
|
42226
|
-
|
|
42314
|
+
if (hasGoalDescription) {
|
|
42315
|
+
return goalDescription;
|
|
42316
|
+
}
|
|
42317
|
+
if (hasPersonaDescription) {
|
|
42318
|
+
return personaDescription;
|
|
42319
|
+
}
|
|
42320
|
+
return null;
|
|
42227
42321
|
}
|
|
42228
42322
|
/**
|
|
42229
42323
|
* Resolves the last INITIAL MESSAGE commitment, which is the public initial-message value.
|
|
@@ -42710,7 +42804,7 @@ async function createAgentModelRequirements(agentSource, modelName, availableMod
|
|
|
42710
42804
|
* Selects the best model using the preparePersona function
|
|
42711
42805
|
* This directly uses preparePersona to ensure DRY principle
|
|
42712
42806
|
*
|
|
42713
|
-
* @param agentSource The agent source to derive
|
|
42807
|
+
* @param agentSource The agent source to derive effective profile text from
|
|
42714
42808
|
* @param llmTools LLM tools for preparing persona
|
|
42715
42809
|
* @returns The name of the best selected model
|
|
42716
42810
|
*
|
|
@@ -42718,9 +42812,9 @@ async function createAgentModelRequirements(agentSource, modelName, availableMod
|
|
|
42718
42812
|
*/
|
|
42719
42813
|
async function selectBestModelUsingPersona(agentSource, llmTools) {
|
|
42720
42814
|
var _a;
|
|
42721
|
-
// Parse agent source to get
|
|
42815
|
+
// Parse agent source to get the effective profile description
|
|
42722
42816
|
const { agentName, personaDescription } = parseAgentSource(agentSource);
|
|
42723
|
-
// Use agent name as fallback if no
|
|
42817
|
+
// Use agent name as fallback if no profile description is available
|
|
42724
42818
|
const description = personaDescription || agentName || 'AI Agent';
|
|
42725
42819
|
try {
|
|
42726
42820
|
// Use preparePersona directly
|
|
@@ -44182,7 +44276,7 @@ var findRefactorCandidates$1 = /*#__PURE__*/Object.freeze({
|
|
|
44182
44276
|
/**
|
|
44183
44277
|
* CLI usage text for this script.
|
|
44184
44278
|
*/
|
|
44185
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push]';
|
|
44279
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-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] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push]';
|
|
44186
44280
|
/**
|
|
44187
44281
|
* Top-level flags supported by this command.
|
|
44188
44282
|
*/
|
|
@@ -44192,6 +44286,8 @@ const KNOWN_OPTION_FLAGS = new Set([
|
|
|
44192
44286
|
'--model',
|
|
44193
44287
|
'--context',
|
|
44194
44288
|
'--test',
|
|
44289
|
+
'--preserve-logs',
|
|
44290
|
+
'--no-ui',
|
|
44195
44291
|
'--thinking-level',
|
|
44196
44292
|
'--priority',
|
|
44197
44293
|
'--allow-credits',
|
|
@@ -44224,6 +44320,8 @@ function parseRunOptions(args) {
|
|
|
44224
44320
|
const context = readOptionValue(args, '--context');
|
|
44225
44321
|
const hasTestCommandFlag = args.includes('--test');
|
|
44226
44322
|
const testCommand = readVariadicOptionValue(args, '--test');
|
|
44323
|
+
const preserveLogs = args.includes('--preserve-logs');
|
|
44324
|
+
const noUi = args.includes('--no-ui');
|
|
44227
44325
|
const hasThinkingLevelFlag = args.includes('--thinking-level');
|
|
44228
44326
|
const thinkingLevelValue = readOptionValue(args, '--thinking-level');
|
|
44229
44327
|
const hasPriorityFlag = args.includes('--priority');
|
|
@@ -44259,6 +44357,8 @@ function parseRunOptions(args) {
|
|
|
44259
44357
|
autoMigrate,
|
|
44260
44358
|
allowDestructiveAutoMigrate,
|
|
44261
44359
|
autoPush,
|
|
44360
|
+
preserveLogs,
|
|
44361
|
+
noUi,
|
|
44262
44362
|
agentName,
|
|
44263
44363
|
model,
|
|
44264
44364
|
context,
|
|
@@ -44339,18 +44439,10 @@ function appendCoderContext(prompt, context) {
|
|
|
44339
44439
|
return `${normalizedPrompt}\n\n${normalizedContext}`;
|
|
44340
44440
|
}
|
|
44341
44441
|
|
|
44342
|
-
/**
|
|
44343
|
-
* Refresh interval for the progress header in milliseconds.
|
|
44344
|
-
*/
|
|
44345
|
-
const PROGRESS_REFRESH_INTERVAL_MS = 1000;
|
|
44346
|
-
/**
|
|
44347
|
-
* Number of terminal lines reserved for the sticky progress header.
|
|
44348
|
-
*/
|
|
44349
|
-
const PROGRESS_HEADER_RESERVED_LINES = 1;
|
|
44350
44442
|
/**
|
|
44351
44443
|
* Calendar formats used when displaying the estimated completion time.
|
|
44352
44444
|
*/
|
|
44353
|
-
const ESTIMATED_DONE_CALENDAR_FORMATS
|
|
44445
|
+
const ESTIMATED_DONE_CALENDAR_FORMATS = {
|
|
44354
44446
|
sameDay: '[Today] h:mm',
|
|
44355
44447
|
nextDay: '[Tomorrow] h:mm',
|
|
44356
44448
|
nextWeek: 'dddd h:mm',
|
|
@@ -44358,6 +44450,121 @@ const ESTIMATED_DONE_CALENDAR_FORMATS$1 = {
|
|
|
44358
44450
|
lastWeek: 'dddd h:mm',
|
|
44359
44451
|
sameElse: 'MMM D h:mm',
|
|
44360
44452
|
};
|
|
44453
|
+
/**
|
|
44454
|
+
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
44455
|
+
*/
|
|
44456
|
+
function formatDurationBrief(duration) {
|
|
44457
|
+
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
44458
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
44459
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
44460
|
+
const seconds = totalSeconds % 60;
|
|
44461
|
+
const parts = [];
|
|
44462
|
+
if (hours > 0) {
|
|
44463
|
+
parts.push(`${hours}h`);
|
|
44464
|
+
}
|
|
44465
|
+
if (minutes > 0) {
|
|
44466
|
+
parts.push(`${minutes}m`);
|
|
44467
|
+
}
|
|
44468
|
+
if (!parts.length && seconds > 0) {
|
|
44469
|
+
parts.push(`${seconds}s`);
|
|
44470
|
+
}
|
|
44471
|
+
if (!parts.length) {
|
|
44472
|
+
parts.push('0s');
|
|
44473
|
+
}
|
|
44474
|
+
return parts.join(' ');
|
|
44475
|
+
}
|
|
44476
|
+
|
|
44477
|
+
/**
|
|
44478
|
+
* Builds a session-scoped progress snapshot from prompt stats and elapsed active time.
|
|
44479
|
+
*/
|
|
44480
|
+
function buildCoderRunProgressSnapshot(stats, elapsedDuration, initialDone) {
|
|
44481
|
+
const totalPrompts = stats.done + stats.forAgent + stats.toBeWritten;
|
|
44482
|
+
const sessionDone = Math.max(0, stats.done - initialDone);
|
|
44483
|
+
const sessionRemaining = stats.forAgent;
|
|
44484
|
+
const sessionTotal = sessionDone + sessionRemaining;
|
|
44485
|
+
const currentPromptIndex = sessionTotal > 0 ? Math.min(sessionDone + 1, sessionTotal) : 0;
|
|
44486
|
+
const percentage = sessionTotal > 0 ? Math.round((sessionDone / sessionTotal) * 100) : 0;
|
|
44487
|
+
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
44488
|
+
let estimatedTotalText = 'estimating...';
|
|
44489
|
+
let estimatedLabel = 'after first completion';
|
|
44490
|
+
let isEstimatedTotalKnown = false;
|
|
44491
|
+
if (sessionTotal > 0 && sessionDone > 0) {
|
|
44492
|
+
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * sessionTotal) / sessionDone;
|
|
44493
|
+
const estimatedRemainingMs = Math.max(0, estimatedTotalMs - elapsedDuration.asMilliseconds());
|
|
44494
|
+
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
44495
|
+
const estimatedCompletion = moment().add(estimatedRemainingMs, 'milliseconds');
|
|
44496
|
+
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
44497
|
+
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
44498
|
+
isEstimatedTotalKnown = true;
|
|
44499
|
+
}
|
|
44500
|
+
return {
|
|
44501
|
+
totalPrompts,
|
|
44502
|
+
sessionDone,
|
|
44503
|
+
sessionRemaining,
|
|
44504
|
+
sessionTotal,
|
|
44505
|
+
currentPromptIndex,
|
|
44506
|
+
skippedPrompts: stats.belowMinimumPriority,
|
|
44507
|
+
toBeWrittenPrompts: stats.toBeWritten,
|
|
44508
|
+
percentage,
|
|
44509
|
+
elapsedText,
|
|
44510
|
+
estimatedTotalText,
|
|
44511
|
+
estimatedLabel,
|
|
44512
|
+
isEstimatedTotalKnown,
|
|
44513
|
+
};
|
|
44514
|
+
}
|
|
44515
|
+
|
|
44516
|
+
/**
|
|
44517
|
+
* Tracks active coder-run time while excluding pauses and user-confirmation waits.
|
|
44518
|
+
*/
|
|
44519
|
+
class CoderRunTimer {
|
|
44520
|
+
/**
|
|
44521
|
+
* Creates a timer anchored at the provided start time.
|
|
44522
|
+
*/
|
|
44523
|
+
constructor(startTime, isPausedInitially = false) {
|
|
44524
|
+
this.startTime = startTime;
|
|
44525
|
+
/**
|
|
44526
|
+
* Total milliseconds spent in paused state across the run.
|
|
44527
|
+
*/
|
|
44528
|
+
this.pausedMs = 0;
|
|
44529
|
+
if (isPausedInitially) {
|
|
44530
|
+
this.pausedSince = startTime.clone();
|
|
44531
|
+
}
|
|
44532
|
+
}
|
|
44533
|
+
/**
|
|
44534
|
+
* Pauses active-time tracking until `resume()` is called.
|
|
44535
|
+
*/
|
|
44536
|
+
pause() {
|
|
44537
|
+
if (this.pausedSince === undefined) {
|
|
44538
|
+
this.pausedSince = moment();
|
|
44539
|
+
}
|
|
44540
|
+
}
|
|
44541
|
+
/**
|
|
44542
|
+
* Resumes active-time tracking after a pause.
|
|
44543
|
+
*/
|
|
44544
|
+
resume() {
|
|
44545
|
+
if (this.pausedSince !== undefined) {
|
|
44546
|
+
this.pausedMs += moment().diff(this.pausedSince);
|
|
44547
|
+
this.pausedSince = undefined;
|
|
44548
|
+
}
|
|
44549
|
+
}
|
|
44550
|
+
/**
|
|
44551
|
+
* Returns the currently accumulated active duration.
|
|
44552
|
+
*/
|
|
44553
|
+
getElapsedDuration() {
|
|
44554
|
+
const wallMs = moment().diff(this.startTime);
|
|
44555
|
+
const currentPauseMs = this.pausedSince !== undefined ? moment().diff(this.pausedSince) : 0;
|
|
44556
|
+
return moment.duration(Math.max(0, wallMs - this.pausedMs - currentPauseMs));
|
|
44557
|
+
}
|
|
44558
|
+
}
|
|
44559
|
+
|
|
44560
|
+
/**
|
|
44561
|
+
* Refresh interval for the progress header in milliseconds.
|
|
44562
|
+
*/
|
|
44563
|
+
const PROGRESS_REFRESH_INTERVAL_MS = 1000;
|
|
44564
|
+
/**
|
|
44565
|
+
* Number of terminal lines reserved for the sticky progress header.
|
|
44566
|
+
*/
|
|
44567
|
+
const PROGRESS_HEADER_RESERVED_LINES = 3;
|
|
44361
44568
|
/**
|
|
44362
44569
|
* Compact CLI progress display that stays pinned at the top of the terminal.
|
|
44363
44570
|
*/
|
|
@@ -44365,11 +44572,12 @@ class CliProgressDisplay {
|
|
|
44365
44572
|
/**
|
|
44366
44573
|
* Creates a new display that uses the provided start time when computing estimates.
|
|
44367
44574
|
*/
|
|
44368
|
-
constructor(startTime) {
|
|
44369
|
-
this.
|
|
44575
|
+
constructor(startTime, minimumPriority) {
|
|
44576
|
+
this.minimumPriority = minimumPriority;
|
|
44370
44577
|
this.stats = { done: 0, forAgent: 0, belowMinimumPriority: 0, toBeWritten: 0 };
|
|
44371
44578
|
this.isHeaderReserved = false;
|
|
44372
44579
|
this.isInteractive = Boolean(process.stdout.isTTY);
|
|
44580
|
+
this.timer = new CoderRunTimer(startTime);
|
|
44373
44581
|
if (!this.isInteractive) {
|
|
44374
44582
|
return;
|
|
44375
44583
|
}
|
|
@@ -44388,6 +44596,20 @@ class CliProgressDisplay {
|
|
|
44388
44596
|
this.stats = stats;
|
|
44389
44597
|
this.render();
|
|
44390
44598
|
}
|
|
44599
|
+
/**
|
|
44600
|
+
* Pauses the active timer while the runner is waiting for user input.
|
|
44601
|
+
*/
|
|
44602
|
+
pauseTimer() {
|
|
44603
|
+
this.timer.pause();
|
|
44604
|
+
this.render();
|
|
44605
|
+
}
|
|
44606
|
+
/**
|
|
44607
|
+
* Resumes the active timer after a pause.
|
|
44608
|
+
*/
|
|
44609
|
+
resumeTimer() {
|
|
44610
|
+
this.timer.resume();
|
|
44611
|
+
this.render();
|
|
44612
|
+
}
|
|
44391
44613
|
/**
|
|
44392
44614
|
* Stops the automatic refresh cycle and renders the final header once more.
|
|
44393
44615
|
*/
|
|
@@ -44405,14 +44627,17 @@ class CliProgressDisplay {
|
|
|
44405
44627
|
* Repaint the header without disturbing the current cursor position.
|
|
44406
44628
|
*/
|
|
44407
44629
|
render() {
|
|
44630
|
+
var _a;
|
|
44408
44631
|
if (!this.isInteractive) {
|
|
44409
44632
|
return;
|
|
44410
44633
|
}
|
|
44411
|
-
const
|
|
44634
|
+
const lines = this.buildProgressLines();
|
|
44412
44635
|
process.stdout.write('\x1b[s');
|
|
44413
|
-
|
|
44414
|
-
|
|
44415
|
-
|
|
44636
|
+
for (let lineIndex = 0; lineIndex < PROGRESS_HEADER_RESERVED_LINES; lineIndex++) {
|
|
44637
|
+
cursorTo(process.stdout, 0, lineIndex);
|
|
44638
|
+
clearLine(process.stdout, 0);
|
|
44639
|
+
process.stdout.write((_a = lines[lineIndex]) !== null && _a !== void 0 ? _a : '');
|
|
44640
|
+
}
|
|
44416
44641
|
process.stdout.write('\x1b[u');
|
|
44417
44642
|
}
|
|
44418
44643
|
/**
|
|
@@ -44426,72 +44651,74 @@ class CliProgressDisplay {
|
|
|
44426
44651
|
this.isHeaderReserved = true;
|
|
44427
44652
|
}
|
|
44428
44653
|
/**
|
|
44429
|
-
* Builds the
|
|
44654
|
+
* Builds the colored progress text padded to the terminal width.
|
|
44430
44655
|
*/
|
|
44431
|
-
|
|
44656
|
+
buildProgressLines() {
|
|
44432
44657
|
var _a, _b;
|
|
44433
|
-
const snapshot =
|
|
44434
|
-
const
|
|
44435
|
-
const
|
|
44436
|
-
|
|
44437
|
-
|
|
44438
|
-
|
|
44439
|
-
|
|
44658
|
+
const snapshot = buildCoderRunProgressSnapshot(this.stats, this.timer.getElapsedDuration(), (_a = this.initialDone) !== null && _a !== void 0 ? _a : this.stats.done);
|
|
44659
|
+
const columns = Math.max(40, (_b = process.stdout.columns) !== null && _b !== void 0 ? _b : 80);
|
|
44660
|
+
const workingLine = snapshot.sessionTotal > 0
|
|
44661
|
+
? [
|
|
44662
|
+
`Working on ${snapshot.currentPromptIndex}/${snapshot.sessionTotal} prompts`,
|
|
44663
|
+
`Priority >=${this.minimumPriority}`,
|
|
44664
|
+
`Repo total ${snapshot.totalPrompts}`,
|
|
44665
|
+
].join(' | ')
|
|
44666
|
+
: [`No runnable prompts`, `Priority >=${this.minimumPriority}`, `Repo total ${snapshot.totalPrompts}`].join(' | ');
|
|
44667
|
+
const detailParts = [
|
|
44668
|
+
`Done ${snapshot.sessionDone}/${snapshot.sessionTotal} this run`,
|
|
44669
|
+
`Elapsed ${snapshot.elapsedText} / ${snapshot.estimatedTotalText}`,
|
|
44670
|
+
`Est. done ${snapshot.estimatedLabel}`,
|
|
44671
|
+
];
|
|
44672
|
+
if (snapshot.skippedPrompts > 0) {
|
|
44673
|
+
detailParts.splice(1, 0, `Skipping ${snapshot.skippedPrompts} prompts with Priority <${this.minimumPriority}`);
|
|
44674
|
+
}
|
|
44675
|
+
if (snapshot.toBeWrittenPrompts > 0) {
|
|
44676
|
+
detailParts.splice(detailParts.length - 2, 0, `Write first ${formatPromptCount$1(snapshot.toBeWrittenPrompts)}`);
|
|
44677
|
+
}
|
|
44678
|
+
const progressLabel = `${snapshot.percentage}% complete (${snapshot.sessionDone}/${snapshot.sessionTotal} done)`;
|
|
44679
|
+
const progressBar = buildProgressBar$1(snapshot.percentage, progressLabel, columns);
|
|
44680
|
+
return [
|
|
44681
|
+
colors.bgCyan.black(padPlainText(workingLine, columns)),
|
|
44682
|
+
colors.bgBlack.white(padPlainText(detailParts.join(' | '), columns)),
|
|
44683
|
+
colors.bgBlack(progressBar),
|
|
44684
|
+
];
|
|
44440
44685
|
}
|
|
44441
44686
|
}
|
|
44442
44687
|
/**
|
|
44443
|
-
*
|
|
44688
|
+
* Builds a colored progress bar with an explicit completion label.
|
|
44444
44689
|
*/
|
|
44445
|
-
function
|
|
44446
|
-
const
|
|
44447
|
-
const
|
|
44448
|
-
const
|
|
44449
|
-
const
|
|
44450
|
-
|
|
44451
|
-
const elapsedDuration = moment.duration(moment().diff(startTime));
|
|
44452
|
-
const elapsedText = formatDurationBrief$1(elapsedDuration);
|
|
44453
|
-
let estimatedTotalText = '—';
|
|
44454
|
-
let estimatedLabel = 'unknown';
|
|
44455
|
-
if (totalPrompts > 0 && completedPrompts > 0) {
|
|
44456
|
-
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / completedPrompts;
|
|
44457
|
-
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
44458
|
-
const estimatedCompletion = startTime.clone().add(estimatedTotalDuration);
|
|
44459
|
-
estimatedTotalText = formatDurationBrief$1(estimatedTotalDuration);
|
|
44460
|
-
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS$1);
|
|
44461
|
-
}
|
|
44462
|
-
return {
|
|
44463
|
-
totalPrompts,
|
|
44464
|
-
completedPrompts,
|
|
44465
|
-
sessionDone,
|
|
44466
|
-
sessionTotal,
|
|
44467
|
-
percentage,
|
|
44468
|
-
elapsedText,
|
|
44469
|
-
estimatedTotalText,
|
|
44470
|
-
estimatedLabel,
|
|
44471
|
-
};
|
|
44690
|
+
function buildProgressBar$1(percentage, label, width) {
|
|
44691
|
+
const safeLabel = ` ${label}`;
|
|
44692
|
+
const barWidth = Math.max(10, width - safeLabel.length);
|
|
44693
|
+
const filledWidth = Math.round((percentage / 100) * barWidth);
|
|
44694
|
+
const emptyWidth = Math.max(0, barWidth - filledWidth);
|
|
44695
|
+
return `${colors.green('█'.repeat(filledWidth))}${colors.gray('░'.repeat(emptyWidth))}${safeLabel}`;
|
|
44472
44696
|
}
|
|
44473
44697
|
/**
|
|
44474
|
-
*
|
|
44698
|
+
* Pads or truncates one plain-text header line to the terminal width.
|
|
44475
44699
|
*/
|
|
44476
|
-
function
|
|
44477
|
-
|
|
44478
|
-
|
|
44479
|
-
|
|
44480
|
-
|
|
44481
|
-
|
|
44482
|
-
if (hours > 0) {
|
|
44483
|
-
parts.push(`${hours}h`);
|
|
44484
|
-
}
|
|
44485
|
-
if (minutes > 0) {
|
|
44486
|
-
parts.push(`${minutes}m`);
|
|
44487
|
-
}
|
|
44488
|
-
if (!parts.length && seconds > 0) {
|
|
44489
|
-
parts.push(`${seconds}s`);
|
|
44490
|
-
}
|
|
44491
|
-
if (!parts.length) {
|
|
44492
|
-
parts.push('0s');
|
|
44700
|
+
function padPlainText(text, width) {
|
|
44701
|
+
if (text.length > width) {
|
|
44702
|
+
if (width <= 3) {
|
|
44703
|
+
return '.'.repeat(width);
|
|
44704
|
+
}
|
|
44705
|
+
return `${text.slice(0, width - 3)}...`;
|
|
44493
44706
|
}
|
|
44494
|
-
return
|
|
44707
|
+
return text.padEnd(width);
|
|
44708
|
+
}
|
|
44709
|
+
/**
|
|
44710
|
+
* Formats a prompt count with the correct singular/plural noun.
|
|
44711
|
+
*/
|
|
44712
|
+
function formatPromptCount$1(count) {
|
|
44713
|
+
return `${count} prompt${count === 1 ? '' : 's'}`;
|
|
44714
|
+
}
|
|
44715
|
+
|
|
44716
|
+
/**
|
|
44717
|
+
* Formats commit message lines for console display.
|
|
44718
|
+
*/
|
|
44719
|
+
function formatCommitMessageForDisplay(message) {
|
|
44720
|
+
const lines = message.split(/\r?\n/);
|
|
44721
|
+
return lines.map((line) => colors.bgBlue.white(` ${line} `)).join('\n');
|
|
44495
44722
|
}
|
|
44496
44723
|
|
|
44497
44724
|
/**
|
|
@@ -44705,14 +44932,6 @@ function normalizeCrLfToLf(content) {
|
|
|
44705
44932
|
return normalized.subarray(0, writeIndex);
|
|
44706
44933
|
}
|
|
44707
44934
|
|
|
44708
|
-
/**
|
|
44709
|
-
* Formats commit message lines for console display.
|
|
44710
|
-
*/
|
|
44711
|
-
function formatCommitMessageForDisplay(message) {
|
|
44712
|
-
const lines = message.split(/\r?\n/);
|
|
44713
|
-
return lines.map((line) => colors.bgBlue.white(` ${line} `)).join('\n');
|
|
44714
|
-
}
|
|
44715
|
-
|
|
44716
44935
|
/**
|
|
44717
44936
|
* Prints the formatted commit message preview.
|
|
44718
44937
|
*/
|
|
@@ -44749,6 +44968,45 @@ async function resolveCoderContext(contextReference, currentWorkingDirectory) {
|
|
|
44749
44968
|
return readFile(contextPath, 'utf-8');
|
|
44750
44969
|
}
|
|
44751
44970
|
|
|
44971
|
+
/**
|
|
44972
|
+
* Builds the temporary live runtime log path for one prompt script and its sibling test script.
|
|
44973
|
+
*/
|
|
44974
|
+
function buildScriptLogPath(scriptPath) {
|
|
44975
|
+
const basePath = scriptPath.replace(/\.test\.sh$/iu, '').replace(/\.sh$/iu, '');
|
|
44976
|
+
return `${basePath}.log.txt`;
|
|
44977
|
+
}
|
|
44978
|
+
|
|
44979
|
+
/**
|
|
44980
|
+
* Decides whether one temporary prompt artifact should be deleted after a round finishes.
|
|
44981
|
+
*/
|
|
44982
|
+
function shouldDeleteTemporaryArtifact({ preserveArtifactsOnSuccess, hasFailed, }) {
|
|
44983
|
+
return !preserveArtifactsOnSuccess && !hasFailed;
|
|
44984
|
+
}
|
|
44985
|
+
|
|
44986
|
+
/**
|
|
44987
|
+
* Runs one prompt-processing round with a dedicated temporary runtime log file that is cleaned up only after successful non-preserved runs.
|
|
44988
|
+
*/
|
|
44989
|
+
async function withPromptRuntimeLog(scriptPath, handler, options) {
|
|
44990
|
+
const logPath = buildScriptLogPath(scriptPath);
|
|
44991
|
+
let hasFailed = false;
|
|
44992
|
+
await unlink(logPath).catch(() => undefined);
|
|
44993
|
+
try {
|
|
44994
|
+
return await handler(logPath);
|
|
44995
|
+
}
|
|
44996
|
+
catch (error) {
|
|
44997
|
+
hasFailed = true;
|
|
44998
|
+
throw error;
|
|
44999
|
+
}
|
|
45000
|
+
finally {
|
|
45001
|
+
if (shouldDeleteTemporaryArtifact({
|
|
45002
|
+
preserveArtifactsOnSuccess: options === null || options === void 0 ? void 0 : options.preserveArtifactsOnSuccess,
|
|
45003
|
+
hasFailed,
|
|
45004
|
+
})) {
|
|
45005
|
+
await unlink(logPath).catch(() => undefined);
|
|
45006
|
+
}
|
|
45007
|
+
}
|
|
45008
|
+
}
|
|
45009
|
+
|
|
44752
45010
|
/**
|
|
44753
45011
|
* Waits for the user to press Enter before continuing.
|
|
44754
45012
|
*/
|
|
@@ -46588,6 +46846,15 @@ function buildPromptLabelForDisplay(file, section) {
|
|
|
46588
46846
|
return `${relative(process.cwd(), file.path).replace(/\\/g, '/')}#${section.startLine + 1}`;
|
|
46589
46847
|
}
|
|
46590
46848
|
|
|
46849
|
+
/**
|
|
46850
|
+
* Extracts a short summary line from a prompt section.
|
|
46851
|
+
*/
|
|
46852
|
+
function buildPromptSummary(file, section) {
|
|
46853
|
+
const lines = buildCodexPrompt(file, section).split(/\r?\n/);
|
|
46854
|
+
const firstLine = lines.find((line) => line.trim() !== '');
|
|
46855
|
+
return (firstLine === null || firstLine === void 0 ? void 0 : firstLine.trim()) || '(empty prompt)';
|
|
46856
|
+
}
|
|
46857
|
+
|
|
46591
46858
|
/**
|
|
46592
46859
|
* Builds the script path for a prompt section.
|
|
46593
46860
|
*/
|
|
@@ -46647,15 +46914,6 @@ function findNextTodoPrompt(files, minimumPriority = 0) {
|
|
|
46647
46914
|
return nextPrompt;
|
|
46648
46915
|
}
|
|
46649
46916
|
|
|
46650
|
-
/**
|
|
46651
|
-
* Extracts a short summary line from a prompt section.
|
|
46652
|
-
*/
|
|
46653
|
-
function buildPromptSummary(file, section) {
|
|
46654
|
-
const lines = buildCodexPrompt(file, section).split(/\r?\n/);
|
|
46655
|
-
const firstLine = lines.find((line) => line.trim() !== '');
|
|
46656
|
-
return (firstLine === null || firstLine === void 0 ? void 0 : firstLine.trim()) || '(empty prompt)';
|
|
46657
|
-
}
|
|
46658
|
-
|
|
46659
46917
|
/**
|
|
46660
46918
|
* Lists upcoming tasks that are ready to run (no authoring placeholders).
|
|
46661
46919
|
*/
|
|
@@ -47052,25 +47310,190 @@ function toPosixPath(filePath) {
|
|
|
47052
47310
|
}
|
|
47053
47311
|
|
|
47054
47312
|
/**
|
|
47055
|
-
*
|
|
47313
|
+
* Environment variable read by the shell wrapper to tee live output into the temporary runtime log file.
|
|
47314
|
+
*/
|
|
47315
|
+
const PTBK_CODER_LOG_FILE_ENV_NAME = 'PTBK_CODER_LOG_FILE';
|
|
47316
|
+
/**
|
|
47317
|
+
* Small bash wrapper that preserves stdout/stderr streams while teeing both into the runtime log file.
|
|
47318
|
+
*/
|
|
47319
|
+
const LOGGED_BASH_WRAPPER_COMMAND = `
|
|
47320
|
+
if [ -n "\${${PTBK_CODER_LOG_FILE_ENV_NAME}:-}" ]; then
|
|
47321
|
+
exec > >(tee -a "\$${PTBK_CODER_LOG_FILE_ENV_NAME}") 2> >(tee -a "\$${PTBK_CODER_LOG_FILE_ENV_NAME}" >&2)
|
|
47322
|
+
fi
|
|
47323
|
+
bash "$1"
|
|
47324
|
+
`.trim();
|
|
47325
|
+
/**
|
|
47326
|
+
* Shapes one bash invocation that optionally mirrors live script output into a temporary log file.
|
|
47327
|
+
*/
|
|
47328
|
+
function buildLoggedBashExecution(scriptPath, logPath) {
|
|
47329
|
+
return {
|
|
47330
|
+
args: ['-lc', LOGGED_BASH_WRAPPER_COMMAND, 'ptbk-coder-temp-script', toPosixPath(scriptPath)],
|
|
47331
|
+
env: logPath ? { [PTBK_CODER_LOG_FILE_ENV_NAME]: toPosixPath(logPath) } : undefined,
|
|
47332
|
+
};
|
|
47333
|
+
}
|
|
47334
|
+
/**
|
|
47335
|
+
* Appends one execution-start section with the raw script input before the shell begins producing output.
|
|
47336
|
+
*/
|
|
47337
|
+
async function appendScriptExecutionLogStart({ scriptPath, scriptContent, logPath, }) {
|
|
47338
|
+
if (!logPath) {
|
|
47339
|
+
return;
|
|
47340
|
+
}
|
|
47341
|
+
await mkdir(dirname(logPath), { recursive: true });
|
|
47342
|
+
const scriptKind = describeTempScriptKind(scriptPath);
|
|
47343
|
+
const normalizedInput = scriptContent.replace(/\r\n/g, '\n').trimEnd();
|
|
47344
|
+
const logSection = [
|
|
47345
|
+
`=== ${scriptKind} started at ${new Date().toISOString()} ===`,
|
|
47346
|
+
`Script path: ${toPosixPath(scriptPath)}`,
|
|
47347
|
+
'',
|
|
47348
|
+
'--- raw input ---',
|
|
47349
|
+
normalizedInput,
|
|
47350
|
+
'',
|
|
47351
|
+
'--- raw output ---',
|
|
47352
|
+
'',
|
|
47353
|
+
].join('\n');
|
|
47354
|
+
await appendFile(logPath, `${logSection}\n`, 'utf-8');
|
|
47355
|
+
}
|
|
47356
|
+
/**
|
|
47357
|
+
* Appends one execution-finish section after the shell settles.
|
|
47358
|
+
*/
|
|
47359
|
+
async function appendScriptExecutionLogFinish({ scriptPath, logPath, status, details, }) {
|
|
47360
|
+
if (!logPath) {
|
|
47361
|
+
return;
|
|
47362
|
+
}
|
|
47363
|
+
const scriptKind = describeTempScriptKind(scriptPath);
|
|
47364
|
+
const logLines = [
|
|
47365
|
+
'',
|
|
47366
|
+
`=== ${scriptKind} finished at ${new Date().toISOString()} ===`,
|
|
47367
|
+
`Status: ${status}`,
|
|
47368
|
+
];
|
|
47369
|
+
if (details !== undefined) {
|
|
47370
|
+
logLines.push('');
|
|
47371
|
+
logLines.push('--- details ---');
|
|
47372
|
+
logLines.push(formatUnknownErrorDetails(details));
|
|
47373
|
+
}
|
|
47374
|
+
logLines.push('');
|
|
47375
|
+
await appendFile(logPath, `${logLines.join('\n')}\n`, 'utf-8');
|
|
47376
|
+
}
|
|
47377
|
+
/**
|
|
47378
|
+
* Distinguishes prompt-runner and verification temp shells in the shared runtime log.
|
|
47379
|
+
*/
|
|
47380
|
+
function describeTempScriptKind(scriptPath) {
|
|
47381
|
+
return scriptPath.toLowerCase().endsWith('.test.sh') ? 'test shell' : 'runner shell';
|
|
47382
|
+
}
|
|
47383
|
+
|
|
47384
|
+
/**
|
|
47385
|
+
* Runs one temporary bash script, optionally mirroring its raw input/output into a live runtime log file.
|
|
47386
|
+
*/
|
|
47387
|
+
async function runBashScriptWithOutput(options) {
|
|
47388
|
+
await appendScriptExecutionLogStart(options);
|
|
47389
|
+
const bashExecution = buildLoggedBashExecution(options.scriptPath, options.logPath);
|
|
47390
|
+
const scriptPathPosix = toPosixPath(options.scriptPath);
|
|
47391
|
+
return await new Promise((resolve, reject) => {
|
|
47392
|
+
const commandProcess = spawn('bash', bashExecution.args, {
|
|
47393
|
+
env: bashExecution.env ? { ...process.env, ...bashExecution.env } : process.env,
|
|
47394
|
+
});
|
|
47395
|
+
let output = '';
|
|
47396
|
+
let settled = false;
|
|
47397
|
+
let isSettling = false;
|
|
47398
|
+
/**
|
|
47399
|
+
* Appends the final log footer before settling.
|
|
47400
|
+
*/
|
|
47401
|
+
const finishLog = async (status, details) => {
|
|
47402
|
+
await appendScriptExecutionLogFinish({
|
|
47403
|
+
scriptPath: options.scriptPath,
|
|
47404
|
+
logPath: options.logPath,
|
|
47405
|
+
status,
|
|
47406
|
+
details,
|
|
47407
|
+
});
|
|
47408
|
+
};
|
|
47409
|
+
/**
|
|
47410
|
+
* Ensures the promise settles only once.
|
|
47411
|
+
*/
|
|
47412
|
+
const settleOnce = (handler) => {
|
|
47413
|
+
if (settled) {
|
|
47414
|
+
return;
|
|
47415
|
+
}
|
|
47416
|
+
settled = true;
|
|
47417
|
+
handler();
|
|
47418
|
+
};
|
|
47419
|
+
/**
|
|
47420
|
+
* Appends the final log footer and settles the promise exactly once.
|
|
47421
|
+
*/
|
|
47422
|
+
const settleWithLog = (status, handler, details) => {
|
|
47423
|
+
if (isSettling || settled) {
|
|
47424
|
+
return;
|
|
47425
|
+
}
|
|
47426
|
+
isSettling = true;
|
|
47427
|
+
void finishLog(status, details).finally(() => {
|
|
47428
|
+
settleOnce(handler);
|
|
47429
|
+
});
|
|
47430
|
+
};
|
|
47431
|
+
commandProcess.stdout.on('data', (stdout) => {
|
|
47432
|
+
const chunk = stdout.toString();
|
|
47433
|
+
output += chunk;
|
|
47434
|
+
console.info(chunk);
|
|
47435
|
+
});
|
|
47436
|
+
commandProcess.stderr.on('data', (stderr) => {
|
|
47437
|
+
const chunk = stderr.toString();
|
|
47438
|
+
output += chunk;
|
|
47439
|
+
if (chunk.trim()) {
|
|
47440
|
+
console.warn(chunk);
|
|
47441
|
+
}
|
|
47442
|
+
});
|
|
47443
|
+
/**
|
|
47444
|
+
* Handles process exit and resolves or rejects accordingly.
|
|
47445
|
+
*/
|
|
47446
|
+
const handleExit = (code) => {
|
|
47447
|
+
if (code === 0) {
|
|
47448
|
+
settleWithLog('succeeded', () => resolve(spaceTrim$1(output)));
|
|
47449
|
+
return;
|
|
47450
|
+
}
|
|
47451
|
+
const failure = new Error(spaceTrim$1(output) || `Command "bash ${scriptPathPosix}" exited with code ${code}`);
|
|
47452
|
+
settleWithLog(`failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}`, () => reject(failure), failure);
|
|
47453
|
+
};
|
|
47454
|
+
commandProcess.on('close', handleExit);
|
|
47455
|
+
commandProcess.on('exit', handleExit);
|
|
47456
|
+
commandProcess.on('disconnect', () => {
|
|
47457
|
+
const failure = new Error(`Command "bash ${scriptPathPosix}" disconnected`);
|
|
47458
|
+
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
47459
|
+
});
|
|
47460
|
+
commandProcess.on('error', (error) => {
|
|
47461
|
+
const failure = new Error(`Command "bash ${scriptPathPosix}" failed: ${error.message}`);
|
|
47462
|
+
settleWithLog('failed before completion', () => reject(failure), failure);
|
|
47463
|
+
});
|
|
47464
|
+
});
|
|
47465
|
+
}
|
|
47466
|
+
|
|
47467
|
+
/**
|
|
47468
|
+
* Creates a temporary script file, runs a handler, and cleans it up unless preservation is requested or the run fails.
|
|
47056
47469
|
*/
|
|
47057
47470
|
async function withTempScript(options, handler) {
|
|
47058
47471
|
const { scriptPath, scriptContent } = options;
|
|
47472
|
+
let hasFailed = false;
|
|
47059
47473
|
await mkdir(dirname$1(scriptPath), { recursive: true });
|
|
47060
47474
|
await writeFile(scriptPath, scriptContent, 'utf-8');
|
|
47061
|
-
|
|
47062
|
-
|
|
47063
|
-
|
|
47475
|
+
try {
|
|
47476
|
+
return await handler(scriptPath);
|
|
47477
|
+
}
|
|
47478
|
+
catch (error) {
|
|
47479
|
+
hasFailed = true;
|
|
47480
|
+
throw error;
|
|
47481
|
+
}
|
|
47482
|
+
finally {
|
|
47483
|
+
if (shouldDeleteTemporaryArtifact({ preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess, hasFailed })) {
|
|
47484
|
+
await unlink(scriptPath).catch(() => undefined);
|
|
47485
|
+
}
|
|
47486
|
+
}
|
|
47064
47487
|
}
|
|
47065
47488
|
|
|
47066
47489
|
/**
|
|
47067
|
-
* Creates a temporary script file, runs it, captures output, and
|
|
47490
|
+
* Creates a temporary script file, runs it, captures output, and cleans it up unless preservation is requested or the run fails.
|
|
47068
47491
|
*/
|
|
47069
47492
|
async function $runGoScriptWithOutput(options) {
|
|
47070
47493
|
return await withTempScript(options, async (scriptPath) => {
|
|
47071
|
-
return await
|
|
47072
|
-
|
|
47073
|
-
|
|
47494
|
+
return await runBashScriptWithOutput({
|
|
47495
|
+
...options,
|
|
47496
|
+
scriptPath,
|
|
47074
47497
|
});
|
|
47075
47498
|
});
|
|
47076
47499
|
}
|
|
@@ -47166,6 +47589,8 @@ class ClaudeCodeRunner {
|
|
|
47166
47589
|
const output = await $runGoScriptWithOutput({
|
|
47167
47590
|
scriptPath: options.scriptPath,
|
|
47168
47591
|
scriptContent,
|
|
47592
|
+
logPath: options.logPath,
|
|
47593
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47169
47594
|
});
|
|
47170
47595
|
const usage = parseClaudeCodeJsonOutput(output);
|
|
47171
47596
|
return { usage };
|
|
@@ -47173,13 +47598,13 @@ class ClaudeCodeRunner {
|
|
|
47173
47598
|
}
|
|
47174
47599
|
|
|
47175
47600
|
/**
|
|
47176
|
-
* Creates a temporary script file, runs it, and
|
|
47601
|
+
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
47177
47602
|
*/
|
|
47178
47603
|
async function $runGoScript(options) {
|
|
47179
47604
|
await withTempScript(options, async (scriptPath) => {
|
|
47180
|
-
await
|
|
47181
|
-
|
|
47182
|
-
|
|
47605
|
+
await runBashScriptWithOutput({
|
|
47606
|
+
...options,
|
|
47607
|
+
scriptPath,
|
|
47183
47608
|
});
|
|
47184
47609
|
});
|
|
47185
47610
|
}
|
|
@@ -47228,6 +47653,8 @@ class ClineRunner {
|
|
|
47228
47653
|
await $runGoScript({
|
|
47229
47654
|
scriptPath: options.scriptPath,
|
|
47230
47655
|
scriptContent,
|
|
47656
|
+
logPath: options.logPath,
|
|
47657
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47231
47658
|
});
|
|
47232
47659
|
return { usage: UNCERTAIN_USAGE };
|
|
47233
47660
|
}
|
|
@@ -47351,6 +47778,8 @@ class GeminiRunner {
|
|
|
47351
47778
|
const output = await $runGoScriptWithOutput({
|
|
47352
47779
|
scriptPath: options.scriptPath,
|
|
47353
47780
|
scriptContent,
|
|
47781
|
+
logPath: options.logPath,
|
|
47782
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47354
47783
|
});
|
|
47355
47784
|
const usage = parseGeminiUsageFromOutput(output, options.prompt, this.options.model);
|
|
47356
47785
|
return { usage };
|
|
@@ -47406,6 +47835,8 @@ class GitHubCopilotRunner {
|
|
|
47406
47835
|
await $runGoScript({
|
|
47407
47836
|
scriptPath: options.scriptPath,
|
|
47408
47837
|
scriptContent,
|
|
47838
|
+
logPath: options.logPath,
|
|
47839
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47409
47840
|
});
|
|
47410
47841
|
return { usage: UNCERTAIN_USAGE };
|
|
47411
47842
|
}
|
|
@@ -47442,14 +47873,30 @@ function buildCommandFailureMessage(scriptPathPosix, code, fullOutput) {
|
|
|
47442
47873
|
async function runScriptUntilMarkerIdle(options) {
|
|
47443
47874
|
const { scriptPath, completionLineMatcher, idleTimeoutMs } = options;
|
|
47444
47875
|
const scriptPathPosix = toPosixPath(scriptPath);
|
|
47876
|
+
await appendScriptExecutionLogStart(options);
|
|
47877
|
+
const bashExecution = buildLoggedBashExecution(scriptPath, options.logPath);
|
|
47445
47878
|
return await new Promise((resolve, reject) => {
|
|
47446
|
-
const commandProcess = spawn('bash',
|
|
47879
|
+
const commandProcess = spawn('bash', bashExecution.args, {
|
|
47880
|
+
env: bashExecution.env ? { ...process.env, ...bashExecution.env } : process.env,
|
|
47881
|
+
});
|
|
47447
47882
|
let stdoutBuffer = '';
|
|
47448
47883
|
let stderrBuffer = '';
|
|
47449
47884
|
let fullOutput = '';
|
|
47450
47885
|
let markerSeen = false;
|
|
47451
47886
|
let idleTimer;
|
|
47452
47887
|
let settled = false;
|
|
47888
|
+
let isSettling = false;
|
|
47889
|
+
/**
|
|
47890
|
+
* Appends the final log footer before settling.
|
|
47891
|
+
*/
|
|
47892
|
+
const finishLog = async (status, details) => {
|
|
47893
|
+
await appendScriptExecutionLogFinish({
|
|
47894
|
+
scriptPath,
|
|
47895
|
+
logPath: options.logPath,
|
|
47896
|
+
status,
|
|
47897
|
+
details,
|
|
47898
|
+
});
|
|
47899
|
+
};
|
|
47453
47900
|
/**
|
|
47454
47901
|
* Ensures the promise settles only once.
|
|
47455
47902
|
*/
|
|
@@ -47464,6 +47911,18 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
47464
47911
|
}
|
|
47465
47912
|
handler();
|
|
47466
47913
|
};
|
|
47914
|
+
/**
|
|
47915
|
+
* Appends the final log footer and settles the promise exactly once.
|
|
47916
|
+
*/
|
|
47917
|
+
const settleWithLog = (status, handler, details) => {
|
|
47918
|
+
if (isSettling || settled) {
|
|
47919
|
+
return;
|
|
47920
|
+
}
|
|
47921
|
+
isSettling = true;
|
|
47922
|
+
void finishLog(status, details).finally(() => {
|
|
47923
|
+
settleOnce(handler);
|
|
47924
|
+
});
|
|
47925
|
+
};
|
|
47467
47926
|
/**
|
|
47468
47927
|
* Resets the idle timer that triggers termination after inactivity.
|
|
47469
47928
|
*/
|
|
@@ -47473,7 +47932,7 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
47473
47932
|
}
|
|
47474
47933
|
idleTimer = setTimeout(() => {
|
|
47475
47934
|
commandProcess.kill();
|
|
47476
|
-
|
|
47935
|
+
settleWithLog('completed after idle timeout', () => resolve(fullOutput));
|
|
47477
47936
|
}, idleTimeoutMs);
|
|
47478
47937
|
};
|
|
47479
47938
|
/**
|
|
@@ -47527,41 +47986,43 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
47527
47986
|
* Handles process exit and resolves or rejects accordingly.
|
|
47528
47987
|
*/
|
|
47529
47988
|
const handleExit = (code) => {
|
|
47530
|
-
|
|
47531
|
-
|
|
47989
|
+
const failure = code === 0 || markerSeen ? undefined : new Error(buildCommandFailureMessage(scriptPathPosix, code, fullOutput));
|
|
47990
|
+
const status = failure ? `failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}` : 'succeeded';
|
|
47991
|
+
settleWithLog(status, () => {
|
|
47992
|
+
if (!failure) {
|
|
47532
47993
|
resolve(fullOutput);
|
|
47533
47994
|
return;
|
|
47534
47995
|
}
|
|
47535
|
-
reject(
|
|
47996
|
+
reject(failure);
|
|
47536
47997
|
});
|
|
47537
47998
|
};
|
|
47538
47999
|
commandProcess.on('close', handleExit);
|
|
47539
48000
|
commandProcess.on('exit', handleExit);
|
|
47540
48001
|
commandProcess.on('disconnect', () => {
|
|
47541
|
-
|
|
47542
|
-
|
|
47543
|
-
});
|
|
48002
|
+
const failure = new Error(buildCommandFailureMessage(scriptPathPosix, null, fullOutput));
|
|
48003
|
+
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
47544
48004
|
});
|
|
47545
48005
|
commandProcess.on('error', (error) => {
|
|
47546
|
-
|
|
47547
|
-
|
|
47548
|
-
|
|
47549
|
-
|
|
47550
|
-
});
|
|
48006
|
+
const outputSnippet = createOutputSnippet(fullOutput);
|
|
48007
|
+
const details = outputSnippet ? `\n\n${outputSnippet}` : '';
|
|
48008
|
+
const failure = new Error(`Command "bash ${scriptPathPosix}" failed: ${error.message}${details}`);
|
|
48009
|
+
settleWithLog('failed before completion', () => reject(failure), failure);
|
|
47551
48010
|
});
|
|
47552
48011
|
});
|
|
47553
48012
|
}
|
|
47554
48013
|
|
|
47555
48014
|
/**
|
|
47556
|
-
* Creates a temporary script file, runs it, waits for a completion marker and idle time, and
|
|
48015
|
+
* Creates a temporary script file, runs it, waits for a completion marker and idle time, and cleans it up unless preservation is requested or the run fails.
|
|
47557
48016
|
* Returns the captured output for post-processing.
|
|
47558
48017
|
*/
|
|
47559
48018
|
async function $runGoScriptUntilMarkerIdle(options) {
|
|
47560
48019
|
return await withTempScript(options, async (scriptPath) => {
|
|
47561
48020
|
return await runScriptUntilMarkerIdle({
|
|
47562
48021
|
scriptPath,
|
|
48022
|
+
scriptContent: options.scriptContent,
|
|
47563
48023
|
completionLineMatcher: options.completionLineMatcher,
|
|
47564
48024
|
idleTimeoutMs: options.idleTimeoutMs,
|
|
48025
|
+
logPath: options.logPath,
|
|
47565
48026
|
});
|
|
47566
48027
|
});
|
|
47567
48028
|
}
|
|
@@ -47939,6 +48400,8 @@ class OpenAiCodexRunner {
|
|
|
47939
48400
|
scriptContent,
|
|
47940
48401
|
completionLineMatcher: CODEX_COMPLETION_LINE,
|
|
47941
48402
|
idleTimeoutMs: CODEX_COMPLETION_IDLE_MS,
|
|
48403
|
+
logPath: options.logPath,
|
|
48404
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47942
48405
|
});
|
|
47943
48406
|
this.rateLimitBackoff.reset();
|
|
47944
48407
|
return { usage: buildCodexUsageFromOutput(output, this.options.model) };
|
|
@@ -48072,6 +48535,8 @@ class OpencodeRunner {
|
|
|
48072
48535
|
output = await $runGoScriptWithOutput({
|
|
48073
48536
|
scriptPath: options.scriptPath,
|
|
48074
48537
|
scriptContent,
|
|
48538
|
+
logPath: options.logPath,
|
|
48539
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48075
48540
|
});
|
|
48076
48541
|
}
|
|
48077
48542
|
catch (error) {
|
|
@@ -48098,6 +48563,8 @@ async function runPromptTestCommand(options) {
|
|
|
48098
48563
|
cd "${projectPath}"
|
|
48099
48564
|
${options.command}
|
|
48100
48565
|
`),
|
|
48566
|
+
logPath: options.logPath,
|
|
48567
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48101
48568
|
});
|
|
48102
48569
|
}
|
|
48103
48570
|
|
|
@@ -48121,6 +48588,8 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48121
48588
|
prompt: options.prompt,
|
|
48122
48589
|
scriptPath: options.scriptPath,
|
|
48123
48590
|
projectPath: options.projectPath,
|
|
48591
|
+
logPath: options.logPath,
|
|
48592
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48124
48593
|
});
|
|
48125
48594
|
return { ...result, attemptCount: 1 };
|
|
48126
48595
|
}
|
|
@@ -48132,6 +48601,8 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48132
48601
|
prompt: promptForCurrentAttempt,
|
|
48133
48602
|
scriptPath: options.scriptPath,
|
|
48134
48603
|
projectPath: options.projectPath,
|
|
48604
|
+
logPath: options.logPath,
|
|
48605
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48135
48606
|
});
|
|
48136
48607
|
console.info(colors.gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
|
|
48137
48608
|
try {
|
|
@@ -48139,6 +48610,8 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48139
48610
|
command: normalizedTestCommand,
|
|
48140
48611
|
projectPath: options.projectPath,
|
|
48141
48612
|
scriptPath: buildPromptTestScriptPath(options.scriptPath),
|
|
48613
|
+
logPath: options.logPath,
|
|
48614
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48142
48615
|
});
|
|
48143
48616
|
return { ...result, attemptCount };
|
|
48144
48617
|
}
|
|
@@ -48220,24 +48693,203 @@ function buildPromptTestScriptPath(scriptPath) {
|
|
|
48220
48693
|
}
|
|
48221
48694
|
|
|
48222
48695
|
/**
|
|
48223
|
-
* Maximum number of
|
|
48224
|
-
*
|
|
48225
|
-
* @private internal constant of coder run UI
|
|
48696
|
+
* Maximum number of output lines reserved for agent output in the UI.
|
|
48226
48697
|
*/
|
|
48227
|
-
const
|
|
48698
|
+
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48228
48699
|
/**
|
|
48229
|
-
*
|
|
48700
|
+
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
48701
|
+
*/
|
|
48702
|
+
function buildCoderRunUiFrame(options) {
|
|
48703
|
+
const totalWidth = Math.max(56, Math.min(options.terminalWidth, 96));
|
|
48704
|
+
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
48705
|
+
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
48706
|
+
const sessionScopeLine = options.progress.sessionTotal > 0
|
|
48707
|
+
? `Working on ${options.progress.currentPromptIndex}/${options.progress.sessionTotal} prompts with Priority ≥${options.config.priority}`
|
|
48708
|
+
: `No runnable prompts with Priority ≥${options.config.priority}`;
|
|
48709
|
+
const sessionCountLine = `Done ${options.progress.sessionDone}/${options.progress.sessionTotal} this run · Repo total ${options.progress.totalPrompts}`;
|
|
48710
|
+
const sessionQueueParts = [];
|
|
48711
|
+
if (options.progress.skippedPrompts > 0) {
|
|
48712
|
+
sessionQueueParts.push(`Skipping ${formatPromptCount(options.progress.skippedPrompts)} with Priority <${options.config.priority}`);
|
|
48713
|
+
}
|
|
48714
|
+
if (options.progress.toBeWrittenPrompts > 0) {
|
|
48715
|
+
sessionQueueParts.push(`Write first ${formatPromptCount(options.progress.toBeWrittenPrompts)}`);
|
|
48716
|
+
}
|
|
48717
|
+
const sessionLines = [
|
|
48718
|
+
`${buildPhaseBadge(options.phase, options.pauseState)} ${fitPlainText(options.statusMessage, totalWidth - 18)}`,
|
|
48719
|
+
sessionScopeLine,
|
|
48720
|
+
sessionCountLine,
|
|
48721
|
+
...(sessionQueueParts.length > 0 ? [sessionQueueParts.join(' · ')] : []),
|
|
48722
|
+
`Elapsed ${options.progress.elapsedText} · Est. total ${options.progress.estimatedTotalText} · Est. done ${options.progress.estimatedLabel}`,
|
|
48723
|
+
buildProgressBar(options.progress.percentage, totalWidth - 6, `${options.progress.percentage}% complete (${options.progress.sessionDone}/${options.progress.sessionTotal} done)`),
|
|
48724
|
+
];
|
|
48725
|
+
const metadataParts = [options.config.agentName || 'No agent selected'];
|
|
48726
|
+
if (options.config.modelName) {
|
|
48727
|
+
metadataParts.push(options.config.modelName);
|
|
48728
|
+
}
|
|
48729
|
+
if (options.config.thinkingLevel) {
|
|
48730
|
+
metadataParts.push(`thinking ${options.config.thinkingLevel}`);
|
|
48731
|
+
}
|
|
48732
|
+
const runnerDetails = [
|
|
48733
|
+
[`${colors.bgCyan.black(' PTBK ')}`, colors.bgBlue.white(' CODER '), colors.bold.white(' Promptbook Coder')]
|
|
48734
|
+
.join(''),
|
|
48735
|
+
metadataParts.join(' · '),
|
|
48736
|
+
buildConfigSummaryLine(options.config),
|
|
48737
|
+
];
|
|
48738
|
+
const currentTaskLines = options.currentPromptLabel
|
|
48739
|
+
? [
|
|
48740
|
+
`${promptStatusPrefix}${colors.bold.white(fitPlainText(options.currentPromptLabel, totalWidth - 8))}`,
|
|
48741
|
+
`Attempt ${options.currentAttempt}/${options.maxAttempts} · ${options.statusMessage}`,
|
|
48742
|
+
...options.detailLines.map((detailLine) => `• ${detailLine}`),
|
|
48743
|
+
]
|
|
48744
|
+
: [options.statusMessage, ...options.detailLines.map((detailLine) => `• ${detailLine}`)];
|
|
48745
|
+
const visibleOutputLines = options.agentOutputLines.length > 0
|
|
48746
|
+
? options.agentOutputLines.slice(-MAX_VISIBLE_OUTPUT_LINES).map((line) => `› ${stripAnsi(line)}`)
|
|
48747
|
+
: ['No live agent output yet.'];
|
|
48748
|
+
const controls = buildControlPills(options.pauseState, options.pendingEnterLabel).join(' ');
|
|
48749
|
+
const frame = [
|
|
48750
|
+
...renderBox('Brand', runnerDetails, totalWidth, colors.cyan.bold),
|
|
48751
|
+
...renderBox('Session', sessionLines, totalWidth, colors.yellow.bold),
|
|
48752
|
+
...renderBox(options.currentPromptLabel ? 'Current task' : 'Queue', currentTaskLines, totalWidth, colors.magenta.bold),
|
|
48753
|
+
...renderBox('Live output', visibleOutputLines, totalWidth, colors.green.bold),
|
|
48754
|
+
];
|
|
48755
|
+
if (options.errors.length > 0) {
|
|
48756
|
+
frame.push(...renderBox('Errors', options.errors.map((errorLine) => `${colors.red('✗')} ${errorLine}`), totalWidth, colors.red.bold));
|
|
48757
|
+
}
|
|
48758
|
+
frame.push(...renderBox('Controls', [controls], totalWidth, colors.white.bold));
|
|
48759
|
+
return frame;
|
|
48760
|
+
}
|
|
48761
|
+
/**
|
|
48762
|
+
* Renders a framed box with a colored title and padded body lines.
|
|
48763
|
+
*/
|
|
48764
|
+
function renderBox(title, lines, totalWidth, colorizeTitle) {
|
|
48765
|
+
const bodyWidth = Math.max(10, totalWidth - 4);
|
|
48766
|
+
const titleText = ` ${title} `;
|
|
48767
|
+
const topBorder = colors.gray('┌') +
|
|
48768
|
+
colorizeTitle(titleText) +
|
|
48769
|
+
colors.gray('─'.repeat(Math.max(0, totalWidth - 2 - titleText.length)) + '┐');
|
|
48770
|
+
const body = lines.map((line) => {
|
|
48771
|
+
const paddedLine = padAnsiText(line, bodyWidth);
|
|
48772
|
+
return colors.gray('│ ') + paddedLine + colors.gray(' │');
|
|
48773
|
+
});
|
|
48774
|
+
const bottomBorder = colors.gray(`└${'─'.repeat(totalWidth - 2)}┘`);
|
|
48775
|
+
return [topBorder, ...body, bottomBorder];
|
|
48776
|
+
}
|
|
48777
|
+
/**
|
|
48778
|
+
* Builds the compact config summary line shown in the branding box.
|
|
48779
|
+
*/
|
|
48780
|
+
function buildConfigSummaryLine(config) {
|
|
48781
|
+
const parts = [`Priority ≥${config.priority}`];
|
|
48782
|
+
if (config.context) {
|
|
48783
|
+
parts.unshift(`Context ${config.context}`);
|
|
48784
|
+
}
|
|
48785
|
+
if (config.testCommand) {
|
|
48786
|
+
parts.push(`Test ${config.testCommand}`);
|
|
48787
|
+
}
|
|
48788
|
+
return parts.join(' · ');
|
|
48789
|
+
}
|
|
48790
|
+
/**
|
|
48791
|
+
* Builds the colored phase badge shown in the session box.
|
|
48792
|
+
*/
|
|
48793
|
+
function buildPhaseBadge(phase, pauseState) {
|
|
48794
|
+
if (pauseState !== 'RUNNING' || phase === 'paused') {
|
|
48795
|
+
return colors.bgYellow.black(' PAUSED ');
|
|
48796
|
+
}
|
|
48797
|
+
switch (phase) {
|
|
48798
|
+
case 'loading':
|
|
48799
|
+
case 'initializing':
|
|
48800
|
+
return colors.bgCyan.black(' LOADING ');
|
|
48801
|
+
case 'running':
|
|
48802
|
+
return colors.bgGreen.black(' RUNNING ');
|
|
48803
|
+
case 'verifying':
|
|
48804
|
+
return colors.bgMagenta.white(' VERIFYING ');
|
|
48805
|
+
case 'waiting':
|
|
48806
|
+
return colors.bgBlue.white(' WAITING ');
|
|
48807
|
+
case 'done':
|
|
48808
|
+
return colors.bgGreen.black(' DONE ');
|
|
48809
|
+
case 'error':
|
|
48810
|
+
return colors.bgRed.white(' ERROR ');
|
|
48811
|
+
default:
|
|
48812
|
+
return colors.bgWhite.black(' READY ');
|
|
48813
|
+
}
|
|
48814
|
+
}
|
|
48815
|
+
/**
|
|
48816
|
+
* Builds the progress bar shown in the session box.
|
|
48817
|
+
*/
|
|
48818
|
+
function buildProgressBar(percentage, availableWidth, label) {
|
|
48819
|
+
const percentageLabel = label;
|
|
48820
|
+
const barWidth = Math.max(10, availableWidth - percentageLabel.length - 1);
|
|
48821
|
+
const filledWidth = Math.round((percentage / 100) * barWidth);
|
|
48822
|
+
const emptyWidth = Math.max(0, barWidth - filledWidth);
|
|
48823
|
+
return `${colors.green('█'.repeat(filledWidth))}${colors.gray('░'.repeat(emptyWidth))} ${percentageLabel}`;
|
|
48824
|
+
}
|
|
48825
|
+
/**
|
|
48826
|
+
* Formats a prompt count with singular/plural wording.
|
|
48827
|
+
*/
|
|
48828
|
+
function formatPromptCount(count) {
|
|
48829
|
+
return `${count} prompt${count === 1 ? '' : 's'}`;
|
|
48830
|
+
}
|
|
48831
|
+
/**
|
|
48832
|
+
* Builds the control pills shown in the footer box.
|
|
48833
|
+
*/
|
|
48834
|
+
function buildControlPills(pauseState, pendingEnterLabel) {
|
|
48835
|
+
const pills = [];
|
|
48836
|
+
if (pendingEnterLabel) {
|
|
48837
|
+
pills.push(colors.bgWhite.black(' ENTER ') + colors.white(` ${pendingEnterLabel}`));
|
|
48838
|
+
}
|
|
48839
|
+
pills.push(pauseState === 'RUNNING'
|
|
48840
|
+
? colors.bgYellow.black(' P ') + colors.white(' Pause')
|
|
48841
|
+
: colors.bgYellow.black(' P ') + colors.white(' Resume'));
|
|
48842
|
+
pills.push(colors.bgRed.white(' CTRL+C ') + colors.white(' Exit'));
|
|
48843
|
+
return pills;
|
|
48844
|
+
}
|
|
48845
|
+
/**
|
|
48846
|
+
* Pads or truncates a possibly ANSI-colored line to the target visible width.
|
|
48847
|
+
*/
|
|
48848
|
+
function padAnsiText(text, width) {
|
|
48849
|
+
const fittedText = fitAnsiText(text, width);
|
|
48850
|
+
return fittedText + ' '.repeat(Math.max(0, width - visibleLength(fittedText)));
|
|
48851
|
+
}
|
|
48852
|
+
/**
|
|
48853
|
+
* Truncates a possibly ANSI-colored line to the target visible width.
|
|
48854
|
+
*/
|
|
48855
|
+
function fitAnsiText(text, width) {
|
|
48856
|
+
if (visibleLength(text) <= width) {
|
|
48857
|
+
return text;
|
|
48858
|
+
}
|
|
48859
|
+
return fitPlainText(stripAnsi(text), width);
|
|
48860
|
+
}
|
|
48861
|
+
/**
|
|
48862
|
+
* Truncates a plain-text line to the target width with an ellipsis.
|
|
48863
|
+
*/
|
|
48864
|
+
function fitPlainText(text, width) {
|
|
48865
|
+
if (text.length <= width) {
|
|
48866
|
+
return text;
|
|
48867
|
+
}
|
|
48868
|
+
if (width <= 3) {
|
|
48869
|
+
return '.'.repeat(width);
|
|
48870
|
+
}
|
|
48871
|
+
return `${text.slice(0, width - 3)}...`;
|
|
48872
|
+
}
|
|
48873
|
+
/**
|
|
48874
|
+
* Measures visible string width by stripping ANSI escape codes.
|
|
48875
|
+
*/
|
|
48876
|
+
function visibleLength(text) {
|
|
48877
|
+
return stripAnsi(text).length;
|
|
48878
|
+
}
|
|
48879
|
+
/**
|
|
48880
|
+
* Strips ANSI escape codes from a string.
|
|
48881
|
+
*/
|
|
48882
|
+
function stripAnsi(text) {
|
|
48883
|
+
// eslint-disable-next-line no-control-regex
|
|
48884
|
+
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48885
|
+
}
|
|
48886
|
+
|
|
48887
|
+
/**
|
|
48888
|
+
* Maximum number of agent output lines kept in the scrolling output area.
|
|
48230
48889
|
*
|
|
48231
48890
|
* @private internal constant of coder run UI
|
|
48232
48891
|
*/
|
|
48233
|
-
const
|
|
48234
|
-
sameDay: '[Today] h:mm',
|
|
48235
|
-
nextDay: '[Tomorrow] h:mm',
|
|
48236
|
-
nextWeek: 'dddd h:mm',
|
|
48237
|
-
lastDay: '[Yesterday] h:mm',
|
|
48238
|
-
lastWeek: 'dddd h:mm',
|
|
48239
|
-
sameElse: 'MMM D h:mm',
|
|
48240
|
-
};
|
|
48892
|
+
const MAX_AGENT_OUTPUT_LINES = 12;
|
|
48241
48893
|
/**
|
|
48242
48894
|
* Reactive state manager for the coder run terminal UI.
|
|
48243
48895
|
*
|
|
@@ -48253,35 +48905,27 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48253
48905
|
this.currentPromptLabel = '';
|
|
48254
48906
|
this.currentAttempt = 1;
|
|
48255
48907
|
this.maxAttempts = 3;
|
|
48908
|
+
this.detailLines = [];
|
|
48256
48909
|
this.agentOutputLines = [];
|
|
48257
48910
|
this.phase = 'initializing';
|
|
48258
48911
|
this.statusMessage = 'Initializing...';
|
|
48259
48912
|
this.errors = [];
|
|
48260
48913
|
this.stats = { done: 0, forAgent: 0, belowMinimumPriority: 0, toBeWritten: 0 };
|
|
48261
|
-
|
|
48262
|
-
* Total milliseconds the timer was paused/waiting (excluded from elapsed display).
|
|
48263
|
-
*/
|
|
48264
|
-
this.pausedMs = 0;
|
|
48265
|
-
this.startTime = startTime;
|
|
48266
|
-
// Timer starts paused — callers call `resumeTimer()` when actual work begins.
|
|
48267
|
-
this.pausedSince = startTime.clone();
|
|
48914
|
+
this.timer = new CoderRunTimer(startTime, true);
|
|
48268
48915
|
}
|
|
48269
48916
|
/**
|
|
48270
48917
|
* Pauses the elapsed timer (e.g. while waiting for user input or paused state).
|
|
48271
48918
|
*/
|
|
48272
48919
|
pauseTimer() {
|
|
48273
|
-
|
|
48274
|
-
|
|
48275
|
-
}
|
|
48920
|
+
this.timer.pause();
|
|
48921
|
+
this.emitChange();
|
|
48276
48922
|
}
|
|
48277
48923
|
/**
|
|
48278
48924
|
* Resumes the elapsed timer after a pause.
|
|
48279
48925
|
*/
|
|
48280
48926
|
resumeTimer() {
|
|
48281
|
-
|
|
48282
|
-
|
|
48283
|
-
this.pausedSince = undefined;
|
|
48284
|
-
}
|
|
48927
|
+
this.timer.resume();
|
|
48928
|
+
this.emitChange();
|
|
48285
48929
|
}
|
|
48286
48930
|
/**
|
|
48287
48931
|
* Replaces the configuration shown in the UI header.
|
|
@@ -48305,41 +48949,15 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48305
48949
|
*/
|
|
48306
48950
|
getProgress() {
|
|
48307
48951
|
var _a;
|
|
48308
|
-
|
|
48309
|
-
const totalPrompts = stats.done + stats.forAgent + stats.toBeWritten;
|
|
48310
|
-
const sessionDone = Math.max(0, stats.done - ((_a = this.initialDone) !== null && _a !== void 0 ? _a : stats.done));
|
|
48311
|
-
const sessionTotal = sessionDone + stats.forAgent;
|
|
48312
|
-
const percentage = totalPrompts > 0 ? Math.round((stats.done / totalPrompts) * 100) : 0;
|
|
48313
|
-
const wallMs = moment().diff(this.startTime);
|
|
48314
|
-
const currentPauseMs = this.pausedSince !== undefined ? moment().diff(this.pausedSince) : 0;
|
|
48315
|
-
const activeMs = Math.max(0, wallMs - this.pausedMs - currentPauseMs);
|
|
48316
|
-
const elapsedDuration = moment.duration(activeMs);
|
|
48317
|
-
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
48318
|
-
let estimatedTotalText = '\u2014';
|
|
48319
|
-
let estimatedLabel = 'unknown';
|
|
48320
|
-
if (totalPrompts > 0 && stats.done > 0) {
|
|
48321
|
-
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / stats.done;
|
|
48322
|
-
const estimatedRemainingMs = estimatedTotalMs - elapsedDuration.asMilliseconds();
|
|
48323
|
-
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
48324
|
-
const estimatedCompletion = moment().add(estimatedRemainingMs, 'milliseconds');
|
|
48325
|
-
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
48326
|
-
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
48327
|
-
}
|
|
48328
|
-
return {
|
|
48329
|
-
totalPrompts,
|
|
48330
|
-
sessionDone,
|
|
48331
|
-
sessionTotal,
|
|
48332
|
-
percentage,
|
|
48333
|
-
elapsedText,
|
|
48334
|
-
estimatedTotalText,
|
|
48335
|
-
estimatedLabel,
|
|
48336
|
-
};
|
|
48952
|
+
return buildCoderRunProgressSnapshot(this.stats, this.timer.getElapsedDuration(), (_a = this.initialDone) !== null && _a !== void 0 ? _a : this.stats.done);
|
|
48337
48953
|
}
|
|
48338
48954
|
/**
|
|
48339
48955
|
* Sets the label of the prompt currently being processed and resets per-prompt state.
|
|
48340
48956
|
*/
|
|
48341
48957
|
setCurrentPrompt(label) {
|
|
48342
48958
|
this.currentPromptLabel = label;
|
|
48959
|
+
this.detailLines = [];
|
|
48960
|
+
this.pendingEnterLabel = undefined;
|
|
48343
48961
|
this.agentOutputLines = [];
|
|
48344
48962
|
this.currentAttempt = 1;
|
|
48345
48963
|
this.emitChange();
|
|
@@ -48379,6 +48997,20 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48379
48997
|
this.statusMessage = message;
|
|
48380
48998
|
this.emitChange();
|
|
48381
48999
|
}
|
|
49000
|
+
/**
|
|
49001
|
+
* Replaces the contextual detail lines shown beneath the current prompt status.
|
|
49002
|
+
*/
|
|
49003
|
+
setDetailLines(detailLines) {
|
|
49004
|
+
this.detailLines = detailLines.filter((detailLine) => detailLine.trim() !== '');
|
|
49005
|
+
this.emitChange();
|
|
49006
|
+
}
|
|
49007
|
+
/**
|
|
49008
|
+
* Sets or clears the Enter-key action label shown in the controls panel.
|
|
49009
|
+
*/
|
|
49010
|
+
setPendingEnterLabel(pendingEnterLabel) {
|
|
49011
|
+
this.pendingEnterLabel = pendingEnterLabel;
|
|
49012
|
+
this.emitChange();
|
|
49013
|
+
}
|
|
48382
49014
|
/**
|
|
48383
49015
|
* Appends an error message to the error list shown in the UI.
|
|
48384
49016
|
*/
|
|
@@ -48390,31 +49022,6 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48390
49022
|
this.emit('change');
|
|
48391
49023
|
}
|
|
48392
49024
|
}
|
|
48393
|
-
/**
|
|
48394
|
-
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
48395
|
-
*
|
|
48396
|
-
* @private internal utility of coder run UI
|
|
48397
|
-
*/
|
|
48398
|
-
function formatDurationBrief(duration) {
|
|
48399
|
-
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
48400
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
48401
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
48402
|
-
const seconds = totalSeconds % 60;
|
|
48403
|
-
const parts = [];
|
|
48404
|
-
if (hours > 0) {
|
|
48405
|
-
parts.push(`${hours}h`);
|
|
48406
|
-
}
|
|
48407
|
-
if (minutes > 0) {
|
|
48408
|
-
parts.push(`${minutes}m`);
|
|
48409
|
-
}
|
|
48410
|
-
if (!parts.length && seconds > 0) {
|
|
48411
|
-
parts.push(`${seconds}s`);
|
|
48412
|
-
}
|
|
48413
|
-
if (!parts.length) {
|
|
48414
|
-
parts.push('0s');
|
|
48415
|
-
}
|
|
48416
|
-
return parts.join(' ');
|
|
48417
|
-
}
|
|
48418
49025
|
|
|
48419
49026
|
/**
|
|
48420
49027
|
* Refresh interval for the terminal UI in milliseconds.
|
|
@@ -48422,18 +49029,6 @@ function formatDurationBrief(duration) {
|
|
|
48422
49029
|
* @private internal constant of coder run UI
|
|
48423
49030
|
*/
|
|
48424
49031
|
const UI_REFRESH_INTERVAL_MS = 200;
|
|
48425
|
-
/**
|
|
48426
|
-
* Character width used for the text progress bar.
|
|
48427
|
-
*
|
|
48428
|
-
* @private internal constant of coder run UI
|
|
48429
|
-
*/
|
|
48430
|
-
const PROGRESS_BAR_WIDTH = 40;
|
|
48431
|
-
/**
|
|
48432
|
-
* Maximum number of output lines reserved for agent output in the UI.
|
|
48433
|
-
*
|
|
48434
|
-
* @private internal constant of coder run UI
|
|
48435
|
-
*/
|
|
48436
|
-
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48437
49032
|
/**
|
|
48438
49033
|
* Spinner animation frames.
|
|
48439
49034
|
*
|
|
@@ -48452,31 +49047,12 @@ const SPINNER_FRAMES = [
|
|
|
48452
49047
|
'\u280F',
|
|
48453
49048
|
];
|
|
48454
49049
|
/**
|
|
48455
|
-
*
|
|
48456
|
-
*
|
|
48457
|
-
* @private internal utility of coder run UI
|
|
48458
|
-
*/
|
|
48459
|
-
function stripAnsi(text) {
|
|
48460
|
-
// eslint-disable-next-line no-control-regex
|
|
48461
|
-
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48462
|
-
}
|
|
48463
|
-
/**
|
|
48464
|
-
* Returns the usable terminal width, capped at 80.
|
|
49050
|
+
* Returns the usable terminal width, capped at 96.
|
|
48465
49051
|
*
|
|
48466
49052
|
* @private internal utility of coder run UI
|
|
48467
49053
|
*/
|
|
48468
49054
|
function getTerminalWidth() {
|
|
48469
|
-
return Math.min(process.stdout.columns || 80,
|
|
48470
|
-
}
|
|
48471
|
-
/**
|
|
48472
|
-
* Builds a text progress bar string from a percentage.
|
|
48473
|
-
*
|
|
48474
|
-
* @private internal utility of coder run UI
|
|
48475
|
-
*/
|
|
48476
|
-
function buildProgressBar(percentage) {
|
|
48477
|
-
const filled = Math.round((percentage / 100) * PROGRESS_BAR_WIDTH);
|
|
48478
|
-
const empty = PROGRESS_BAR_WIDTH - filled;
|
|
48479
|
-
return colors.green('\u2588'.repeat(filled)) + colors.gray('\u2591'.repeat(empty)) + ` ${percentage}%`;
|
|
49055
|
+
return Math.min(process.stdout.columns || 80, 96);
|
|
48480
49056
|
}
|
|
48481
49057
|
/**
|
|
48482
49058
|
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
@@ -48497,21 +49073,20 @@ function renderCoderRunUi(startTime) {
|
|
|
48497
49073
|
state,
|
|
48498
49074
|
startCapturingAgentOutput: () => { },
|
|
48499
49075
|
stopCapturingAgentOutput: () => { },
|
|
49076
|
+
waitForEnter: async () => { },
|
|
48500
49077
|
cleanup: () => { },
|
|
48501
49078
|
};
|
|
48502
49079
|
}
|
|
48503
|
-
// --- Console interception ---
|
|
48504
49080
|
const originalConsoleInfo = console.info;
|
|
48505
49081
|
const originalConsoleWarn = console.warn;
|
|
48506
49082
|
const originalConsoleError = console.error;
|
|
48507
49083
|
const originalConsoleLog = console.log;
|
|
48508
49084
|
let isCapturing = false;
|
|
49085
|
+
let pendingEnterResolver;
|
|
48509
49086
|
console.info = (...args) => {
|
|
48510
49087
|
if (isCapturing) {
|
|
48511
49088
|
state.addAgentOutput(args.map(String).join(' '));
|
|
48512
49089
|
}
|
|
48513
|
-
// In UI mode, non-captured output is intentionally suppressed
|
|
48514
|
-
// so it does not interfere with the repainted frame.
|
|
48515
49090
|
};
|
|
48516
49091
|
console.warn = (...args) => {
|
|
48517
49092
|
if (isCapturing) {
|
|
@@ -48528,29 +49103,11 @@ function renderCoderRunUi(startTime) {
|
|
|
48528
49103
|
state.addAgentOutput(args.map(String).join(' '));
|
|
48529
49104
|
}
|
|
48530
49105
|
};
|
|
48531
|
-
// --- Keyboard input (pause) ---
|
|
48532
49106
|
const readline = require('readline');
|
|
48533
49107
|
readline.emitKeypressEvents(process.stdin);
|
|
48534
49108
|
if (process.stdin.isTTY) {
|
|
48535
49109
|
process.stdin.setRawMode(true);
|
|
48536
49110
|
}
|
|
48537
|
-
const keypressHandler = (_str, key) => {
|
|
48538
|
-
if (key.ctrl && key.name === 'c') {
|
|
48539
|
-
cleanup();
|
|
48540
|
-
process.exit(0);
|
|
48541
|
-
}
|
|
48542
|
-
if (key.name === 'p') {
|
|
48543
|
-
const current = getPauseState();
|
|
48544
|
-
if (current === 'RUNNING') {
|
|
48545
|
-
requestPause();
|
|
48546
|
-
}
|
|
48547
|
-
else {
|
|
48548
|
-
requestResume();
|
|
48549
|
-
}
|
|
48550
|
-
}
|
|
48551
|
-
};
|
|
48552
|
-
process.stdin.on('keypress', keypressHandler);
|
|
48553
|
-
// --- Rendering ---
|
|
48554
49111
|
let spinnerFrame = 0;
|
|
48555
49112
|
let previousFrameLineCount = 0;
|
|
48556
49113
|
let isRendering = false;
|
|
@@ -48578,8 +49135,22 @@ function renderCoderRunUi(startTime) {
|
|
|
48578
49135
|
}
|
|
48579
49136
|
isRendering = true;
|
|
48580
49137
|
try {
|
|
48581
|
-
const lines =
|
|
48582
|
-
|
|
49138
|
+
const lines = buildCoderRunUiFrame({
|
|
49139
|
+
terminalWidth: getTerminalWidth(),
|
|
49140
|
+
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
49141
|
+
pauseState: getPauseState(),
|
|
49142
|
+
config: state.config,
|
|
49143
|
+
phase: state.phase,
|
|
49144
|
+
currentPromptLabel: state.currentPromptLabel,
|
|
49145
|
+
currentAttempt: state.currentAttempt,
|
|
49146
|
+
maxAttempts: state.maxAttempts,
|
|
49147
|
+
statusMessage: state.statusMessage,
|
|
49148
|
+
detailLines: state.detailLines,
|
|
49149
|
+
pendingEnterLabel: state.pendingEnterLabel,
|
|
49150
|
+
agentOutputLines: state.agentOutputLines,
|
|
49151
|
+
errors: state.errors,
|
|
49152
|
+
progress: state.getProgress(),
|
|
49153
|
+
});
|
|
48583
49154
|
if (previousFrameLineCount > 0) {
|
|
48584
49155
|
process.stdout.write(`\x1b[${previousFrameLineCount}A`);
|
|
48585
49156
|
}
|
|
@@ -48591,14 +49162,12 @@ function renderCoderRunUi(startTime) {
|
|
|
48591
49162
|
process.stdout.write('\n');
|
|
48592
49163
|
}
|
|
48593
49164
|
}
|
|
48594
|
-
// Clear any leftover lines from a previous longer frame.
|
|
48595
49165
|
if (lines.length < previousFrameLineCount) {
|
|
48596
49166
|
for (let i = lines.length; i < previousFrameLineCount; i++) {
|
|
48597
49167
|
process.stdout.write('\n');
|
|
48598
49168
|
clearLine(process.stdout, 0);
|
|
48599
49169
|
cursorTo(process.stdout, 0);
|
|
48600
49170
|
}
|
|
48601
|
-
// Move back up to the end of the current frame.
|
|
48602
49171
|
const overshoot = previousFrameLineCount - lines.length;
|
|
48603
49172
|
if (overshoot > 0) {
|
|
48604
49173
|
process.stdout.write(`\x1b[${overshoot}A`);
|
|
@@ -48611,94 +49180,35 @@ function renderCoderRunUi(startTime) {
|
|
|
48611
49180
|
isRendering = false;
|
|
48612
49181
|
}
|
|
48613
49182
|
}
|
|
48614
|
-
|
|
48615
|
-
|
|
48616
|
-
|
|
48617
|
-
|
|
48618
|
-
const w = getTerminalWidth();
|
|
48619
|
-
const sep = colors.gray('\u2500'.repeat(w - 2));
|
|
48620
|
-
const spinner = SPINNER_FRAMES[spinnerFrame];
|
|
48621
|
-
const { config, phase, currentPromptLabel, currentAttempt, maxAttempts, statusMessage, agentOutputLines, errors, } = state;
|
|
48622
|
-
const progress = state.getProgress();
|
|
48623
|
-
const isPaused = getPauseState() !== 'RUNNING';
|
|
48624
|
-
const isActive = phase === 'running' || phase === 'verifying' || phase === 'loading';
|
|
48625
|
-
const lines = [];
|
|
48626
|
-
// --- Branding ---
|
|
48627
|
-
lines.push(colors.bold.cyan('\u2728 Promptbook Coder'));
|
|
48628
|
-
// --- Config ---
|
|
48629
|
-
let configLine1 = `Agent: ${colors.bold.green(config.agentName)}`;
|
|
48630
|
-
if (config.modelName) {
|
|
48631
|
-
configLine1 += ` \u2502 Model: ${colors.bold(config.modelName)}`;
|
|
48632
|
-
}
|
|
48633
|
-
if (config.thinkingLevel) {
|
|
48634
|
-
configLine1 += ` \u2502 Thinking: ${colors.bold(config.thinkingLevel)}`;
|
|
48635
|
-
}
|
|
48636
|
-
lines.push(configLine1);
|
|
48637
|
-
let configLine2 = '';
|
|
48638
|
-
if (config.context) {
|
|
48639
|
-
configLine2 += `Context: ${colors.yellow(config.context)} \u2502 `;
|
|
48640
|
-
}
|
|
48641
|
-
configLine2 += `Priority: \u2265${config.priority}`;
|
|
48642
|
-
if (config.testCommand) {
|
|
48643
|
-
configLine2 += ` \u2502 Test: ${colors.gray(config.testCommand)}`;
|
|
48644
|
-
}
|
|
48645
|
-
lines.push(configLine2);
|
|
48646
|
-
// --- Separator ---
|
|
48647
|
-
lines.push(sep);
|
|
48648
|
-
// --- Progress ---
|
|
48649
|
-
const progressSummary = [
|
|
48650
|
-
`${progress.sessionDone}/${progress.sessionTotal} Prompts (${progress.totalPrompts} total)`,
|
|
48651
|
-
`${progress.elapsedText}/${progress.estimatedTotalText}`,
|
|
48652
|
-
`Est. done ${progress.estimatedLabel}`,
|
|
48653
|
-
].join(' \u2502 ');
|
|
48654
|
-
lines.push(progressSummary);
|
|
48655
|
-
lines.push(buildProgressBar(progress.percentage));
|
|
48656
|
-
// --- Separator ---
|
|
48657
|
-
lines.push(sep);
|
|
48658
|
-
// --- Current prompt ---
|
|
48659
|
-
if (currentPromptLabel) {
|
|
48660
|
-
const spinnerPrefix = isActive ? colors.yellow(`${spinner} `) : ' ';
|
|
48661
|
-
lines.push(spinnerPrefix + colors.bold(currentPromptLabel));
|
|
48662
|
-
lines.push(colors.gray(`Attempt ${currentAttempt}/${maxAttempts} \u2502 ${statusMessage}`));
|
|
49183
|
+
const keypressHandler = (_str, key) => {
|
|
49184
|
+
if (key.ctrl && key.name === 'c') {
|
|
49185
|
+
cleanup();
|
|
49186
|
+
process.exit(0);
|
|
48663
49187
|
}
|
|
48664
|
-
|
|
48665
|
-
|
|
48666
|
-
|
|
48667
|
-
|
|
48668
|
-
|
|
48669
|
-
|
|
48670
|
-
|
|
48671
|
-
|
|
48672
|
-
|
|
48673
|
-
|
|
48674
|
-
|
|
48675
|
-
|
|
48676
|
-
|
|
48677
|
-
|
|
48678
|
-
}
|
|
48679
|
-
|
|
48680
|
-
|
|
48681
|
-
lines.push('');
|
|
48682
|
-
for (const err of errors) {
|
|
48683
|
-
lines.push(colors.red(`\u2717 ${err}`));
|
|
48684
|
-
}
|
|
48685
|
-
}
|
|
48686
|
-
// --- Separator ---
|
|
48687
|
-
lines.push(sep);
|
|
48688
|
-
// --- Controls ---
|
|
48689
|
-
const pauseLabel = isPaused
|
|
48690
|
-
? colors.bgYellow.black(' PAUSED ') + colors.gray(' [P] Resume \u2502 Ctrl+C Exit')
|
|
48691
|
-
: colors.gray('[P] Pause \u2502 Ctrl+C Exit');
|
|
48692
|
-
lines.push(pauseLabel);
|
|
48693
|
-
return lines;
|
|
48694
|
-
}
|
|
48695
|
-
// Initial render.
|
|
49188
|
+
if (key.name === 'p') {
|
|
49189
|
+
if (getPauseState() === 'RUNNING') {
|
|
49190
|
+
requestPause();
|
|
49191
|
+
}
|
|
49192
|
+
else {
|
|
49193
|
+
requestResume();
|
|
49194
|
+
}
|
|
49195
|
+
return;
|
|
49196
|
+
}
|
|
49197
|
+
if ((key.name === 'return' || key.name === 'enter') && pendingEnterResolver) {
|
|
49198
|
+
const resolvePendingEnter = pendingEnterResolver;
|
|
49199
|
+
pendingEnterResolver = undefined;
|
|
49200
|
+
state.setPendingEnterLabel(undefined);
|
|
49201
|
+
resolvePendingEnter();
|
|
49202
|
+
}
|
|
49203
|
+
};
|
|
49204
|
+
process.stdin.on('keypress', keypressHandler);
|
|
48696
49205
|
process.stdout.write('\n');
|
|
48697
49206
|
render();
|
|
48698
49207
|
const interval = setInterval(scheduleRender, UI_REFRESH_INTERVAL_MS);
|
|
48699
|
-
// Listen for state changes and schedule a re-render (debounced).
|
|
48700
49208
|
state.on('change', scheduleRender);
|
|
48701
|
-
|
|
49209
|
+
/**
|
|
49210
|
+
* Tears down the terminal UI and restores console / stdin state.
|
|
49211
|
+
*/
|
|
48702
49212
|
function cleanup() {
|
|
48703
49213
|
clearInterval(interval);
|
|
48704
49214
|
state.off('change', scheduleRender);
|
|
@@ -48706,12 +49216,14 @@ function renderCoderRunUi(startTime) {
|
|
|
48706
49216
|
if (process.stdin.isTTY) {
|
|
48707
49217
|
process.stdin.setRawMode(false);
|
|
48708
49218
|
}
|
|
49219
|
+
const resolvePendingEnter = pendingEnterResolver;
|
|
49220
|
+
pendingEnterResolver = undefined;
|
|
49221
|
+
resolvePendingEnter === null || resolvePendingEnter === void 0 ? void 0 : resolvePendingEnter();
|
|
48709
49222
|
isCapturing = false;
|
|
48710
49223
|
console.info = originalConsoleInfo;
|
|
48711
49224
|
console.warn = originalConsoleWarn;
|
|
48712
49225
|
console.error = originalConsoleError;
|
|
48713
49226
|
console.log = originalConsoleLog;
|
|
48714
|
-
// Render one final frame so the user sees the last state.
|
|
48715
49227
|
render();
|
|
48716
49228
|
process.stdout.write('\n');
|
|
48717
49229
|
}
|
|
@@ -48723,6 +49235,19 @@ function renderCoderRunUi(startTime) {
|
|
|
48723
49235
|
stopCapturingAgentOutput() {
|
|
48724
49236
|
isCapturing = false;
|
|
48725
49237
|
},
|
|
49238
|
+
waitForEnter(actionLabel) {
|
|
49239
|
+
if (pendingEnterResolver) {
|
|
49240
|
+
throw new Error('Coder run UI is already waiting for Enter.');
|
|
49241
|
+
}
|
|
49242
|
+
state.setPendingEnterLabel(actionLabel);
|
|
49243
|
+
scheduleRender();
|
|
49244
|
+
return new Promise((resolve) => {
|
|
49245
|
+
pendingEnterResolver = () => {
|
|
49246
|
+
scheduleRender();
|
|
49247
|
+
resolve();
|
|
49248
|
+
};
|
|
49249
|
+
});
|
|
49250
|
+
},
|
|
48726
49251
|
cleanup,
|
|
48727
49252
|
};
|
|
48728
49253
|
}
|
|
@@ -48790,11 +49315,11 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48790
49315
|
`));
|
|
48791
49316
|
}
|
|
48792
49317
|
const runStartDate = moment();
|
|
48793
|
-
const
|
|
48794
|
-
const progressDisplay = options.dryRun ||
|
|
48795
|
-
const uiHandle =
|
|
49318
|
+
const isRichUiEnabled = !options.dryRun && !options.noUi && Boolean(process.stdout.isTTY);
|
|
49319
|
+
const progressDisplay = options.dryRun || options.noUi || isRichUiEnabled ? undefined : new CliProgressDisplay(runStartDate, options.priority);
|
|
49320
|
+
const uiHandle = isRichUiEnabled ? renderCoderRunUi(runStartDate) : undefined;
|
|
48796
49321
|
// When the Ink UI is active it handles keyboard input itself, so skip the raw stdin listener.
|
|
48797
|
-
if (!
|
|
49322
|
+
if (!isRichUiEnabled) {
|
|
48798
49323
|
listenForPause();
|
|
48799
49324
|
}
|
|
48800
49325
|
try {
|
|
@@ -48910,17 +49435,19 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48910
49435
|
let hasWaitedForStart = false;
|
|
48911
49436
|
while (just(true)) {
|
|
48912
49437
|
await checkPause({
|
|
48913
|
-
silent:
|
|
49438
|
+
silent: isRichUiEnabled,
|
|
48914
49439
|
onPaused: () => {
|
|
49440
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
48915
49441
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
48916
49442
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('paused');
|
|
48917
49443
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Paused');
|
|
48918
49444
|
},
|
|
48919
49445
|
onResumed: () => {
|
|
49446
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
48920
49447
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48921
49448
|
},
|
|
48922
49449
|
});
|
|
48923
|
-
if (
|
|
49450
|
+
if (isRichUiEnabled) {
|
|
48924
49451
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
48925
49452
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Loading prompts...');
|
|
48926
49453
|
}
|
|
@@ -48928,17 +49455,17 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48928
49455
|
const stats = summarizePrompts(promptFiles, options.priority);
|
|
48929
49456
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|
|
48930
49457
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(stats);
|
|
48931
|
-
if (!
|
|
49458
|
+
if (!isRichUiEnabled) {
|
|
48932
49459
|
printStats(stats, options.priority);
|
|
48933
49460
|
}
|
|
48934
49461
|
const nextPrompt = findNextTodoPrompt(promptFiles, options.priority);
|
|
48935
49462
|
if (!hasShownUpcomingTasks) {
|
|
48936
|
-
if (stats.toBeWritten > 0 && !
|
|
49463
|
+
if (stats.toBeWritten > 0 && !isRichUiEnabled) {
|
|
48937
49464
|
console.info(colors.yellow('Following prompts need to be written:'));
|
|
48938
49465
|
printPromptsToBeWritten(promptFiles, options.priority);
|
|
48939
49466
|
console.info('');
|
|
48940
49467
|
}
|
|
48941
|
-
if (!
|
|
49468
|
+
if (!isRichUiEnabled) {
|
|
48942
49469
|
printUpcomingTasks(listUpcomingTasks(promptFiles, options.priority));
|
|
48943
49470
|
}
|
|
48944
49471
|
hasShownUpcomingTasks = true;
|
|
@@ -48948,7 +49475,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48948
49475
|
const message = 'No prompts ready for agent.';
|
|
48949
49476
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
48950
49477
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
48951
|
-
if (!
|
|
49478
|
+
if (!isRichUiEnabled) {
|
|
48952
49479
|
console.info(colors.yellow(message));
|
|
48953
49480
|
}
|
|
48954
49481
|
}
|
|
@@ -48956,16 +49483,28 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48956
49483
|
const message = 'All prompts are done.';
|
|
48957
49484
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
48958
49485
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
48959
|
-
if (!
|
|
49486
|
+
if (!isRichUiEnabled) {
|
|
48960
49487
|
console.info(colors.green(message));
|
|
48961
49488
|
}
|
|
48962
49489
|
}
|
|
48963
49490
|
return;
|
|
48964
49491
|
}
|
|
49492
|
+
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
48965
49493
|
if (options.waitForUser) {
|
|
49494
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
48966
49495
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
48967
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.
|
|
48968
|
-
|
|
49496
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
49497
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
49498
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(hasWaitedForStart ? 'Waiting for confirmation to continue' : 'Waiting for confirmation to start');
|
|
49499
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([buildPromptSummary(nextPrompt.file, nextPrompt.section)]);
|
|
49500
|
+
if (isRichUiEnabled) {
|
|
49501
|
+
await (uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.waitForEnter(hasWaitedForStart ? 'Continue' : 'Start'));
|
|
49502
|
+
}
|
|
49503
|
+
else {
|
|
49504
|
+
await waitForPromptStart(nextPrompt.file, nextPrompt.section, !hasWaitedForStart);
|
|
49505
|
+
}
|
|
49506
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([]);
|
|
49507
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
48969
49508
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48970
49509
|
hasWaitedForStart = true;
|
|
48971
49510
|
}
|
|
@@ -48975,8 +49514,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48975
49514
|
const commitMessage = buildCommitMessage(nextPrompt.file, nextPrompt.section);
|
|
48976
49515
|
const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
|
|
48977
49516
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
48978
|
-
|
|
48979
|
-
if (isUiMode) {
|
|
49517
|
+
if (isRichUiEnabled) {
|
|
48980
49518
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
48981
49519
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
48982
49520
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
@@ -48989,55 +49527,71 @@ async function runCodexPrompts(providedOptions) {
|
|
|
48989
49527
|
const roundChangedFilesSnapshot = options.normalizeLineEndings
|
|
48990
49528
|
? await captureChangedFilesSnapshot(process.cwd())
|
|
48991
49529
|
: undefined;
|
|
48992
|
-
|
|
48993
|
-
|
|
48994
|
-
|
|
48995
|
-
|
|
48996
|
-
|
|
48997
|
-
|
|
48998
|
-
|
|
48999
|
-
|
|
49000
|
-
|
|
49001
|
-
|
|
49002
|
-
|
|
49003
|
-
|
|
49004
|
-
|
|
49005
|
-
|
|
49006
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.
|
|
49530
|
+
await withPromptRuntimeLog(scriptPath, async (logPath) => {
|
|
49531
|
+
try {
|
|
49532
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
49533
|
+
const result = await runPromptWithTestFeedback({
|
|
49534
|
+
runner,
|
|
49535
|
+
prompt: codexPrompt,
|
|
49536
|
+
scriptPath,
|
|
49537
|
+
projectPath: process.cwd(),
|
|
49538
|
+
promptLabel,
|
|
49539
|
+
testCommand: options.testCommand,
|
|
49540
|
+
preserveArtifactsOnSuccess: options.preserveLogs,
|
|
49541
|
+
logPath,
|
|
49542
|
+
onAttemptStarted: (nextAttemptCount) => {
|
|
49543
|
+
attemptCount = nextAttemptCount;
|
|
49544
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
|
|
49545
|
+
if (nextAttemptCount > 1) {
|
|
49546
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
|
|
49547
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
|
|
49548
|
+
}
|
|
49549
|
+
},
|
|
49550
|
+
});
|
|
49551
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49552
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
|
|
49553
|
+
markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
|
|
49554
|
+
await writePromptFile(nextPrompt.file);
|
|
49555
|
+
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49556
|
+
if (options.waitForUser) {
|
|
49557
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49558
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49559
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
49560
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Review the commit preview and confirm to continue');
|
|
49561
|
+
if (isRichUiEnabled) {
|
|
49562
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines(formatCommitMessageForDisplay(commitMessage)
|
|
49563
|
+
.split(/\r?\n/)
|
|
49564
|
+
.map((line) => line.trim()));
|
|
49565
|
+
await (uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.waitForEnter('Commit'));
|
|
49566
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([]);
|
|
49007
49567
|
}
|
|
49008
|
-
|
|
49009
|
-
|
|
49010
|
-
|
|
49011
|
-
|
|
49012
|
-
|
|
49013
|
-
|
|
49014
|
-
|
|
49015
|
-
|
|
49016
|
-
|
|
49017
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Waiting... Press Enter to commit');
|
|
49018
|
-
printCommitMessage(commitMessage);
|
|
49019
|
-
await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
|
|
49020
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49568
|
+
else {
|
|
49569
|
+
printCommitMessage(commitMessage);
|
|
49570
|
+
await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
|
|
49571
|
+
}
|
|
49572
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49573
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49574
|
+
}
|
|
49575
|
+
await commitChanges(commitMessage, { autoPush: options.autoPush });
|
|
49576
|
+
await runPostPromptAutoMigrationIfEnabled(options);
|
|
49021
49577
|
}
|
|
49022
|
-
|
|
49023
|
-
|
|
49024
|
-
|
|
49025
|
-
|
|
49026
|
-
|
|
49027
|
-
|
|
49028
|
-
|
|
49029
|
-
|
|
49030
|
-
|
|
49031
|
-
|
|
49032
|
-
|
|
49033
|
-
|
|
49034
|
-
|
|
49035
|
-
|
|
49036
|
-
error
|
|
49037
|
-
}
|
|
49038
|
-
|
|
49039
|
-
throw error;
|
|
49040
|
-
}
|
|
49578
|
+
catch (error) {
|
|
49579
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49580
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
49581
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
49582
|
+
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
49583
|
+
await writePromptFile(nextPrompt.file);
|
|
49584
|
+
await writePromptErrorLog({
|
|
49585
|
+
file: nextPrompt.file,
|
|
49586
|
+
section: nextPrompt.section,
|
|
49587
|
+
runnerName: runnerMetadata.runnerName,
|
|
49588
|
+
modelName: runnerMetadata.modelName,
|
|
49589
|
+
error,
|
|
49590
|
+
});
|
|
49591
|
+
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49592
|
+
throw error;
|
|
49593
|
+
}
|
|
49594
|
+
}, { preserveArtifactsOnSuccess: options.preserveLogs });
|
|
49041
49595
|
}
|
|
49042
49596
|
}
|
|
49043
49597
|
finally {
|