@promptbook/cli 0.112.0-44 → 0.112.0-46
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 +868 -524
- 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/shouldDeleteTemporaryArtifact.d.ts +7 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/withPromptRuntimeLog.d.ts +4 -3
- package/esm/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -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/coderRunUiRefresh.d.ts +17 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +6 -3
- 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/avatarVisualRegistry.test.d.ts +1 -0
- package/esm/src/avatars/visuals/fractalAvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/minecraftAvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/octopus2AvatarVisual.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/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 +868 -524
- 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/shouldDeleteTemporaryArtifact.d.ts +7 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/withPromptRuntimeLog.d.ts +4 -3
- package/umd/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +3 -1
- package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -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/coderRunUiRefresh.d.ts +17 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +6 -3
- 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/avatarVisualRegistry.test.d.ts +1 -0
- package/umd/src/avatars/visuals/fractalAvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/minecraftAvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/octopus2AvatarVisual.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/commitments/STYLE/STYLE.d.ts +9 -2
- package/umd/src/version.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/common/runGoScript/PromptRoundArtifacts.d.ts +0 -35
- package/umd/scripts/run-codex-prompts/common/runGoScript/PromptRoundArtifacts.d.ts +0 -35
package/esm/index.es.js
CHANGED
|
@@ -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-46';
|
|
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,19 +3022,21 @@ 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');
|
|
3026
3030
|
command.option('--ignore-git-changes', 'Skip clean working tree check before running prompts', false);
|
|
3027
3031
|
command.option('--allow-credits', 'Allow OpenAI Codex runner to spend credits when rate limits are exhausted', false);
|
|
3028
|
-
command.option('--preserve-logs', 'Keep generated runner shells and runtime logs after successful prompt rounds; failures keep them automatically', false);
|
|
3029
3032
|
command.option('--no-normalize-line-endings', 'Disable automatic LF normalization for files changed in each coding round');
|
|
3030
3033
|
command.option('--auto-push', 'Automatically git push after each commit', false);
|
|
3031
3034
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
3032
3035
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
3033
3036
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
3034
|
-
const { dryRun, agent, model, context, test, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits,
|
|
3037
|
+
const { dryRun, agent, model, context, test, preserveLogs, ui, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
|
|
3035
3038
|
const testCommand = normalizeCommandOptionValue(test);
|
|
3039
|
+
const noUi = !ui;
|
|
3036
3040
|
// Validate agent
|
|
3037
3041
|
let agentName = undefined;
|
|
3038
3042
|
if (agent) {
|
|
@@ -3062,11 +3066,12 @@ function $initializeCoderRunCommand(program) {
|
|
|
3062
3066
|
model,
|
|
3063
3067
|
context,
|
|
3064
3068
|
testCommand,
|
|
3069
|
+
preserveLogs,
|
|
3070
|
+
noUi,
|
|
3065
3071
|
thinkingLevel,
|
|
3066
3072
|
priority,
|
|
3067
3073
|
normalizeLineEndings,
|
|
3068
3074
|
allowCredits,
|
|
3069
|
-
preserveLogs,
|
|
3070
3075
|
autoMigrate,
|
|
3071
3076
|
allowDestructiveAutoMigrate,
|
|
3072
3077
|
autoPush,
|
|
@@ -18386,7 +18391,7 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18386
18391
|
DELETE Casual conversational style
|
|
18387
18392
|
REMOVE All emoji usage
|
|
18388
18393
|
GOAL Provide professional business communications
|
|
18389
|
-
|
|
18394
|
+
WRITING RULES Use formal language and proper business etiquette
|
|
18390
18395
|
\`\`\`
|
|
18391
18396
|
|
|
18392
18397
|
\`\`\`book
|
|
@@ -18397,7 +18402,7 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18397
18402
|
DISCARD Technical jargon explanations
|
|
18398
18403
|
CANCEL Advanced troubleshooting procedures
|
|
18399
18404
|
GOAL Help users with simple, easy-to-follow solutions
|
|
18400
|
-
|
|
18405
|
+
WRITING RULES Use plain language that anyone can understand
|
|
18401
18406
|
\`\`\`
|
|
18402
18407
|
|
|
18403
18408
|
\`\`\`book
|
|
@@ -18414,11 +18419,11 @@ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18414
18419
|
Concise Information Provider
|
|
18415
18420
|
|
|
18416
18421
|
PERSONA You are a helpful assistant who provides detailed explanations
|
|
18417
|
-
|
|
18422
|
+
WRITING RULES Include examples, analogies, and comprehensive context
|
|
18418
18423
|
CANCEL Detailed explanation style
|
|
18419
18424
|
DISCARD Examples and analogies
|
|
18420
18425
|
GOAL Provide brief, direct answers without unnecessary elaboration
|
|
18421
|
-
|
|
18426
|
+
WRITING RULES Be concise and to the point
|
|
18422
18427
|
\`\`\`
|
|
18423
18428
|
`);
|
|
18424
18429
|
}
|
|
@@ -18602,7 +18607,7 @@ class FormatCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18602
18607
|
PERSONA You are a data analysis expert
|
|
18603
18608
|
FORMAT Present results in structured tables
|
|
18604
18609
|
FORMAT Include confidence scores for all predictions
|
|
18605
|
-
|
|
18610
|
+
WRITING RULES Be concise and precise in explanations
|
|
18606
18611
|
\`\`\`
|
|
18607
18612
|
`);
|
|
18608
18613
|
}
|
|
@@ -18996,7 +19001,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
18996
19001
|
|
|
18997
19002
|
GOAL Help students understand mathematical concepts clearly
|
|
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
|
|
@@ -19410,7 +19415,7 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
19410
19415
|
KNOWLEDGE Academic research requires careful citation and verification
|
|
19411
19416
|
KNOWLEDGE https://example.com/research-guidelines.pdf
|
|
19412
19417
|
ACTION Can help with literature reviews and data analysis
|
|
19413
|
-
|
|
19418
|
+
WRITING RULES Present information in clear, academic format
|
|
19414
19419
|
\`\`\`
|
|
19415
19420
|
`);
|
|
19416
19421
|
}
|
|
@@ -21161,7 +21166,7 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21161
21166
|
|
|
21162
21167
|
META IMAGE https://example.com/professional-avatar.jpg
|
|
21163
21168
|
PERSONA You are a professional business assistant
|
|
21164
|
-
|
|
21169
|
+
WRITING RULES Maintain a formal and courteous tone
|
|
21165
21170
|
\`\`\`
|
|
21166
21171
|
|
|
21167
21172
|
\`\`\`book
|
|
@@ -21169,7 +21174,7 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21169
21174
|
|
|
21170
21175
|
META IMAGE /assets/creative-bot-avatar.png
|
|
21171
21176
|
PERSONA You are a creative and inspiring assistant
|
|
21172
|
-
|
|
21177
|
+
WRITING RULES Be enthusiastic and encouraging
|
|
21173
21178
|
ACTION Can help with brainstorming and ideation
|
|
21174
21179
|
\`\`\`
|
|
21175
21180
|
`);
|
|
@@ -21328,7 +21333,7 @@ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21328
21333
|
META LINK https://twitter.com/devhandle
|
|
21329
21334
|
PERSONA You are an experienced open source developer
|
|
21330
21335
|
ACTION Can help with code reviews and architecture decisions
|
|
21331
|
-
|
|
21336
|
+
WRITING RULES Be direct and technical in explanations
|
|
21332
21337
|
\`\`\`
|
|
21333
21338
|
`);
|
|
21334
21339
|
}
|
|
@@ -21534,7 +21539,7 @@ class ModelCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21534
21539
|
MODEL TEMPERATURE 0.8
|
|
21535
21540
|
MODEL TOP_P 0.9
|
|
21536
21541
|
MODEL MAX_TOKENS 2048
|
|
21537
|
-
|
|
21542
|
+
WRITING RULES Be imaginative and expressive
|
|
21538
21543
|
ACTION Can help with storytelling and character development
|
|
21539
21544
|
\`\`\`
|
|
21540
21545
|
|
|
@@ -21746,7 +21751,7 @@ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
21746
21751
|
NOTE Uses RAG for accessing latest research papers
|
|
21747
21752
|
PERSONA You are a knowledgeable research assistant
|
|
21748
21753
|
ACTION Can help with literature reviews and citations
|
|
21749
|
-
|
|
21754
|
+
WRITING RULES Present information in academic format
|
|
21750
21755
|
\`\`\`
|
|
21751
21756
|
`);
|
|
21752
21757
|
}
|
|
@@ -22040,7 +22045,7 @@ class RuleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22040
22045
|
RULE Always ask for clarification if the user's request is ambiguous
|
|
22041
22046
|
RULE Be polite and professional in all interactions
|
|
22042
22047
|
RULES Never provide medical or legal advice
|
|
22043
|
-
|
|
22048
|
+
WRITING RULES Maintain a friendly and helpful tone
|
|
22044
22049
|
\`\`\`
|
|
22045
22050
|
|
|
22046
22051
|
\`\`\`book
|
|
@@ -22309,8 +22314,8 @@ class ScenarioCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22309
22314
|
/**
|
|
22310
22315
|
* STYLE commitment definition
|
|
22311
22316
|
*
|
|
22312
|
-
*
|
|
22313
|
-
*
|
|
22317
|
+
* Deprecated legacy writing-style commitment kept for backward compatibility.
|
|
22318
|
+
* New books should prefer `WRITING RULES` for writing-only constraints.
|
|
22314
22319
|
*
|
|
22315
22320
|
* Example usage in agent source:
|
|
22316
22321
|
*
|
|
@@ -22329,7 +22334,16 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22329
22334
|
* Short one-line description of STYLE.
|
|
22330
22335
|
*/
|
|
22331
22336
|
get description() {
|
|
22332
|
-
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
|
+
};
|
|
22333
22347
|
}
|
|
22334
22348
|
/**
|
|
22335
22349
|
* Icon for this commitment.
|
|
@@ -22344,15 +22358,34 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
22344
22358
|
return spaceTrim$1(`
|
|
22345
22359
|
# ${this.type}
|
|
22346
22360
|
|
|
22347
|
-
|
|
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.
|
|
22348
22369
|
|
|
22349
22370
|
## Key aspects
|
|
22350
22371
|
|
|
22351
|
-
-
|
|
22372
|
+
- \`${this.type}\` remains functional for backward compatibility only.
|
|
22352
22373
|
- Later style instructions can override earlier ones.
|
|
22353
22374
|
- Style affects both tone and presentation format.
|
|
22354
22375
|
|
|
22355
|
-
##
|
|
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
|
|
22356
22389
|
|
|
22357
22390
|
\`\`\`book
|
|
22358
22391
|
Technical Writer
|
|
@@ -23093,7 +23126,7 @@ class TemplateCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
23093
23126
|
|
|
23094
23127
|
PERSONA You are a helpful customer support representative
|
|
23095
23128
|
TEMPLATE Always structure your response with: 1) Acknowledgment, 2) Solution, 3) Follow-up question
|
|
23096
|
-
|
|
23129
|
+
WRITING RULES Be professional and empathetic
|
|
23097
23130
|
\`\`\`
|
|
23098
23131
|
|
|
23099
23132
|
\`\`\`book
|
|
@@ -23537,7 +23570,7 @@ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
|
|
|
23537
23570
|
|
|
23538
23571
|
PERSONA You are a news analyst who stays up-to-date with current events
|
|
23539
23572
|
USE BROWSER
|
|
23540
|
-
|
|
23573
|
+
WRITING RULES Present news in a balanced and objective manner
|
|
23541
23574
|
ACTION Can search for and summarize news articles
|
|
23542
23575
|
\`\`\`
|
|
23543
23576
|
|
|
@@ -44243,7 +44276,7 @@ var findRefactorCandidates$1 = /*#__PURE__*/Object.freeze({
|
|
|
44243
44276
|
/**
|
|
44244
44277
|
* CLI usage text for this script.
|
|
44245
44278
|
*/
|
|
44246
|
-
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] [--
|
|
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]';
|
|
44247
44280
|
/**
|
|
44248
44281
|
* Top-level flags supported by this command.
|
|
44249
44282
|
*/
|
|
@@ -44253,10 +44286,11 @@ const KNOWN_OPTION_FLAGS = new Set([
|
|
|
44253
44286
|
'--model',
|
|
44254
44287
|
'--context',
|
|
44255
44288
|
'--test',
|
|
44289
|
+
'--preserve-logs',
|
|
44290
|
+
'--no-ui',
|
|
44256
44291
|
'--thinking-level',
|
|
44257
44292
|
'--priority',
|
|
44258
44293
|
'--allow-credits',
|
|
44259
|
-
'--preserve-logs',
|
|
44260
44294
|
'--auto-migrate',
|
|
44261
44295
|
'--allow-destructive-auto-migrate',
|
|
44262
44296
|
'--no-wait',
|
|
@@ -44286,6 +44320,8 @@ function parseRunOptions(args) {
|
|
|
44286
44320
|
const context = readOptionValue(args, '--context');
|
|
44287
44321
|
const hasTestCommandFlag = args.includes('--test');
|
|
44288
44322
|
const testCommand = readVariadicOptionValue(args, '--test');
|
|
44323
|
+
const preserveLogs = args.includes('--preserve-logs');
|
|
44324
|
+
const noUi = args.includes('--no-ui');
|
|
44289
44325
|
const hasThinkingLevelFlag = args.includes('--thinking-level');
|
|
44290
44326
|
const thinkingLevelValue = readOptionValue(args, '--thinking-level');
|
|
44291
44327
|
const hasPriorityFlag = args.includes('--priority');
|
|
@@ -44293,7 +44329,6 @@ function parseRunOptions(args) {
|
|
|
44293
44329
|
const ignoreGitChanges = args.includes('--ignore-git-changes');
|
|
44294
44330
|
const normalizeLineEndings = !args.includes('--no-normalize-line-endings');
|
|
44295
44331
|
const allowCredits = args.includes('--allow-credits');
|
|
44296
|
-
const preserveLogs = args.includes('--preserve-logs');
|
|
44297
44332
|
const autoMigrate = args.includes('--auto-migrate');
|
|
44298
44333
|
const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
|
|
44299
44334
|
const autoPush = args.includes('--auto-push');
|
|
@@ -44319,10 +44354,11 @@ function parseRunOptions(args) {
|
|
|
44319
44354
|
ignoreGitChanges,
|
|
44320
44355
|
normalizeLineEndings,
|
|
44321
44356
|
allowCredits,
|
|
44322
|
-
preserveLogs,
|
|
44323
44357
|
autoMigrate,
|
|
44324
44358
|
allowDestructiveAutoMigrate,
|
|
44325
44359
|
autoPush,
|
|
44360
|
+
preserveLogs,
|
|
44361
|
+
noUi,
|
|
44326
44362
|
agentName,
|
|
44327
44363
|
model,
|
|
44328
44364
|
context,
|
|
@@ -44403,18 +44439,10 @@ function appendCoderContext(prompt, context) {
|
|
|
44403
44439
|
return `${normalizedPrompt}\n\n${normalizedContext}`;
|
|
44404
44440
|
}
|
|
44405
44441
|
|
|
44406
|
-
/**
|
|
44407
|
-
* Refresh interval for the progress header in milliseconds.
|
|
44408
|
-
*/
|
|
44409
|
-
const PROGRESS_REFRESH_INTERVAL_MS = 1000;
|
|
44410
|
-
/**
|
|
44411
|
-
* Number of terminal lines reserved for the sticky progress header.
|
|
44412
|
-
*/
|
|
44413
|
-
const PROGRESS_HEADER_RESERVED_LINES = 1;
|
|
44414
44442
|
/**
|
|
44415
44443
|
* Calendar formats used when displaying the estimated completion time.
|
|
44416
44444
|
*/
|
|
44417
|
-
const ESTIMATED_DONE_CALENDAR_FORMATS
|
|
44445
|
+
const ESTIMATED_DONE_CALENDAR_FORMATS = {
|
|
44418
44446
|
sameDay: '[Today] h:mm',
|
|
44419
44447
|
nextDay: '[Tomorrow] h:mm',
|
|
44420
44448
|
nextWeek: 'dddd h:mm',
|
|
@@ -44422,6 +44450,121 @@ const ESTIMATED_DONE_CALENDAR_FORMATS$1 = {
|
|
|
44422
44450
|
lastWeek: 'dddd h:mm',
|
|
44423
44451
|
sameElse: 'MMM D h:mm',
|
|
44424
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;
|
|
44425
44568
|
/**
|
|
44426
44569
|
* Compact CLI progress display that stays pinned at the top of the terminal.
|
|
44427
44570
|
*/
|
|
@@ -44429,11 +44572,12 @@ class CliProgressDisplay {
|
|
|
44429
44572
|
/**
|
|
44430
44573
|
* Creates a new display that uses the provided start time when computing estimates.
|
|
44431
44574
|
*/
|
|
44432
|
-
constructor(startTime) {
|
|
44433
|
-
this.
|
|
44575
|
+
constructor(startTime, minimumPriority) {
|
|
44576
|
+
this.minimumPriority = minimumPriority;
|
|
44434
44577
|
this.stats = { done: 0, forAgent: 0, belowMinimumPriority: 0, toBeWritten: 0 };
|
|
44435
44578
|
this.isHeaderReserved = false;
|
|
44436
44579
|
this.isInteractive = Boolean(process.stdout.isTTY);
|
|
44580
|
+
this.timer = new CoderRunTimer(startTime);
|
|
44437
44581
|
if (!this.isInteractive) {
|
|
44438
44582
|
return;
|
|
44439
44583
|
}
|
|
@@ -44452,6 +44596,20 @@ class CliProgressDisplay {
|
|
|
44452
44596
|
this.stats = stats;
|
|
44453
44597
|
this.render();
|
|
44454
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
|
+
}
|
|
44455
44613
|
/**
|
|
44456
44614
|
* Stops the automatic refresh cycle and renders the final header once more.
|
|
44457
44615
|
*/
|
|
@@ -44469,14 +44627,17 @@ class CliProgressDisplay {
|
|
|
44469
44627
|
* Repaint the header without disturbing the current cursor position.
|
|
44470
44628
|
*/
|
|
44471
44629
|
render() {
|
|
44630
|
+
var _a;
|
|
44472
44631
|
if (!this.isInteractive) {
|
|
44473
44632
|
return;
|
|
44474
44633
|
}
|
|
44475
|
-
const
|
|
44634
|
+
const lines = this.buildProgressLines();
|
|
44476
44635
|
process.stdout.write('\x1b[s');
|
|
44477
|
-
|
|
44478
|
-
|
|
44479
|
-
|
|
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
|
+
}
|
|
44480
44641
|
process.stdout.write('\x1b[u');
|
|
44481
44642
|
}
|
|
44482
44643
|
/**
|
|
@@ -44490,72 +44651,74 @@ class CliProgressDisplay {
|
|
|
44490
44651
|
this.isHeaderReserved = true;
|
|
44491
44652
|
}
|
|
44492
44653
|
/**
|
|
44493
|
-
* Builds the
|
|
44654
|
+
* Builds the colored progress text padded to the terminal width.
|
|
44494
44655
|
*/
|
|
44495
|
-
|
|
44656
|
+
buildProgressLines() {
|
|
44496
44657
|
var _a, _b;
|
|
44497
|
-
const snapshot =
|
|
44498
|
-
const
|
|
44499
|
-
const
|
|
44500
|
-
|
|
44501
|
-
|
|
44502
|
-
|
|
44503
|
-
|
|
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
|
+
];
|
|
44504
44685
|
}
|
|
44505
44686
|
}
|
|
44506
44687
|
/**
|
|
44507
|
-
*
|
|
44688
|
+
* Builds a colored progress bar with an explicit completion label.
|
|
44508
44689
|
*/
|
|
44509
|
-
function
|
|
44510
|
-
const
|
|
44511
|
-
const
|
|
44512
|
-
const
|
|
44513
|
-
const
|
|
44514
|
-
|
|
44515
|
-
const elapsedDuration = moment.duration(moment().diff(startTime));
|
|
44516
|
-
const elapsedText = formatDurationBrief$1(elapsedDuration);
|
|
44517
|
-
let estimatedTotalText = '—';
|
|
44518
|
-
let estimatedLabel = 'unknown';
|
|
44519
|
-
if (totalPrompts > 0 && completedPrompts > 0) {
|
|
44520
|
-
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / completedPrompts;
|
|
44521
|
-
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
44522
|
-
const estimatedCompletion = startTime.clone().add(estimatedTotalDuration);
|
|
44523
|
-
estimatedTotalText = formatDurationBrief$1(estimatedTotalDuration);
|
|
44524
|
-
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS$1);
|
|
44525
|
-
}
|
|
44526
|
-
return {
|
|
44527
|
-
totalPrompts,
|
|
44528
|
-
completedPrompts,
|
|
44529
|
-
sessionDone,
|
|
44530
|
-
sessionTotal,
|
|
44531
|
-
percentage,
|
|
44532
|
-
elapsedText,
|
|
44533
|
-
estimatedTotalText,
|
|
44534
|
-
estimatedLabel,
|
|
44535
|
-
};
|
|
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}`;
|
|
44536
44696
|
}
|
|
44537
44697
|
/**
|
|
44538
|
-
*
|
|
44698
|
+
* Pads or truncates one plain-text header line to the terminal width.
|
|
44539
44699
|
*/
|
|
44540
|
-
function
|
|
44541
|
-
|
|
44542
|
-
|
|
44543
|
-
|
|
44544
|
-
|
|
44545
|
-
|
|
44546
|
-
if (hours > 0) {
|
|
44547
|
-
parts.push(`${hours}h`);
|
|
44548
|
-
}
|
|
44549
|
-
if (minutes > 0) {
|
|
44550
|
-
parts.push(`${minutes}m`);
|
|
44551
|
-
}
|
|
44552
|
-
if (!parts.length && seconds > 0) {
|
|
44553
|
-
parts.push(`${seconds}s`);
|
|
44554
|
-
}
|
|
44555
|
-
if (!parts.length) {
|
|
44556
|
-
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)}...`;
|
|
44557
44706
|
}
|
|
44558
|
-
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');
|
|
44559
44722
|
}
|
|
44560
44723
|
|
|
44561
44724
|
/**
|
|
@@ -44769,14 +44932,6 @@ function normalizeCrLfToLf(content) {
|
|
|
44769
44932
|
return normalized.subarray(0, writeIndex);
|
|
44770
44933
|
}
|
|
44771
44934
|
|
|
44772
|
-
/**
|
|
44773
|
-
* Formats commit message lines for console display.
|
|
44774
|
-
*/
|
|
44775
|
-
function formatCommitMessageForDisplay(message) {
|
|
44776
|
-
const lines = message.split(/\r?\n/);
|
|
44777
|
-
return lines.map((line) => colors.bgBlue.white(` ${line} `)).join('\n');
|
|
44778
|
-
}
|
|
44779
|
-
|
|
44780
44935
|
/**
|
|
44781
44936
|
* Prints the formatted commit message preview.
|
|
44782
44937
|
*/
|
|
@@ -44822,82 +44977,36 @@ function buildScriptLogPath(scriptPath) {
|
|
|
44822
44977
|
}
|
|
44823
44978
|
|
|
44824
44979
|
/**
|
|
44825
|
-
*
|
|
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.
|
|
44826
44988
|
*/
|
|
44827
|
-
async function withPromptRuntimeLog(scriptPath, handler,
|
|
44989
|
+
async function withPromptRuntimeLog(scriptPath, handler, options) {
|
|
44828
44990
|
const logPath = buildScriptLogPath(scriptPath);
|
|
44991
|
+
let hasFailed = false;
|
|
44829
44992
|
await unlink(logPath).catch(() => undefined);
|
|
44830
|
-
promptRoundArtifacts === null || promptRoundArtifacts === void 0 ? void 0 : promptRoundArtifacts.track(logPath, 'runtime-log');
|
|
44831
44993
|
try {
|
|
44832
44994
|
return await handler(logPath);
|
|
44833
44995
|
}
|
|
44996
|
+
catch (error) {
|
|
44997
|
+
hasFailed = true;
|
|
44998
|
+
throw error;
|
|
44999
|
+
}
|
|
44834
45000
|
finally {
|
|
44835
|
-
if (
|
|
45001
|
+
if (shouldDeleteTemporaryArtifact({
|
|
45002
|
+
preserveArtifactsOnSuccess: options === null || options === void 0 ? void 0 : options.preserveArtifactsOnSuccess,
|
|
45003
|
+
hasFailed,
|
|
45004
|
+
})) {
|
|
44836
45005
|
await unlink(logPath).catch(() => undefined);
|
|
44837
45006
|
}
|
|
44838
45007
|
}
|
|
44839
45008
|
}
|
|
44840
45009
|
|
|
44841
|
-
/**
|
|
44842
|
-
* Shared artifact kinds preserved for debugging when a prompt round fails.
|
|
44843
|
-
*/
|
|
44844
|
-
const FAILURE_PRESERVED_ARTIFACT_KINDS = new Set(['runner-script', 'runtime-log']);
|
|
44845
|
-
/**
|
|
44846
|
-
* Shared artifact kinds preserved after a successful prompt round when explicitly requested.
|
|
44847
|
-
*/
|
|
44848
|
-
const SUCCESS_PRESERVED_ARTIFACT_KINDS = new Set(['runner-script', 'runtime-log']);
|
|
44849
|
-
/**
|
|
44850
|
-
* Empty preserved-artifact set used for successful rounds without `--preserve-logs`.
|
|
44851
|
-
*/
|
|
44852
|
-
const NO_PRESERVED_ARTIFACT_KINDS = new Set();
|
|
44853
|
-
/**
|
|
44854
|
-
* Tracks temporary prompt-round artifacts and deletes only those not preserved for the final round outcome.
|
|
44855
|
-
*/
|
|
44856
|
-
class PromptRoundArtifacts {
|
|
44857
|
-
/**
|
|
44858
|
-
* Creates a new prompt-round artifact tracker.
|
|
44859
|
-
*/
|
|
44860
|
-
constructor(preservedArtifactKindsByOutcome) {
|
|
44861
|
-
this.preservedArtifactKindsByOutcome = preservedArtifactKindsByOutcome;
|
|
44862
|
-
this.trackedArtifacts = new Map();
|
|
44863
|
-
}
|
|
44864
|
-
/**
|
|
44865
|
-
* Registers one temporary artifact for round-final cleanup.
|
|
44866
|
-
*/
|
|
44867
|
-
track(path, kind) {
|
|
44868
|
-
this.trackedArtifacts.set(path, kind);
|
|
44869
|
-
}
|
|
44870
|
-
/**
|
|
44871
|
-
* Cleans up all tracked artifacts that should not survive the final round outcome.
|
|
44872
|
-
*/
|
|
44873
|
-
async cleanup(outcome) {
|
|
44874
|
-
const preservedArtifactKinds = this.preservedArtifactKindsByOutcome[outcome];
|
|
44875
|
-
const trackedArtifacts = [...this.trackedArtifacts.entries()];
|
|
44876
|
-
this.trackedArtifacts.clear();
|
|
44877
|
-
await Promise.all(trackedArtifacts.map(async ([path, kind]) => {
|
|
44878
|
-
if (preservedArtifactKinds.has(kind)) {
|
|
44879
|
-
return;
|
|
44880
|
-
}
|
|
44881
|
-
await unlink(path).catch(() => undefined);
|
|
44882
|
-
}));
|
|
44883
|
-
}
|
|
44884
|
-
}
|
|
44885
|
-
/**
|
|
44886
|
-
* Creates the default artifact-retention policy used by `ptbk coder run`.
|
|
44887
|
-
*/
|
|
44888
|
-
function createCoderRunPromptRoundArtifacts(isPreserveLogs) {
|
|
44889
|
-
return new PromptRoundArtifacts({
|
|
44890
|
-
success: isPreserveLogs ? SUCCESS_PRESERVED_ARTIFACT_KINDS : NO_PRESERVED_ARTIFACT_KINDS,
|
|
44891
|
-
failure: FAILURE_PRESERVED_ARTIFACT_KINDS,
|
|
44892
|
-
});
|
|
44893
|
-
}
|
|
44894
|
-
/**
|
|
44895
|
-
* Derives the tracked artifact kind from one temporary shell path.
|
|
44896
|
-
*/
|
|
44897
|
-
function getPromptRoundArtifactKindFromScriptPath(scriptPath) {
|
|
44898
|
-
return scriptPath.toLowerCase().endsWith('.test.sh') ? 'test-script' : 'runner-script';
|
|
44899
|
-
}
|
|
44900
|
-
|
|
44901
45010
|
/**
|
|
44902
45011
|
* Waits for the user to press Enter before continuing.
|
|
44903
45012
|
*/
|
|
@@ -45335,7 +45444,8 @@ function stringifyUnknownError$1(error) {
|
|
|
45335
45444
|
|
|
45336
45445
|
/**
|
|
45337
45446
|
* Commits staged changes with the provided message using the dedicated coding-agent identity when configured,
|
|
45338
|
-
* otherwise falls back to the default Git configuration. Remote pushing is opt-in via `options.autoPush
|
|
45447
|
+
* otherwise falls back to the default Git configuration. Remote pushing is opt-in via `options.autoPush`,
|
|
45448
|
+
* while `options.excludePaths` can keep temporary artifacts out of the created commit.
|
|
45339
45449
|
*/
|
|
45340
45450
|
async function commitChanges(message, options) {
|
|
45341
45451
|
const projectPath = process.cwd();
|
|
@@ -45345,11 +45455,7 @@ async function commitChanges(message, options) {
|
|
|
45345
45455
|
try {
|
|
45346
45456
|
const agentEnv = buildAgentGitEnv();
|
|
45347
45457
|
const signingFlag = buildAgentGitSigningFlag();
|
|
45348
|
-
await
|
|
45349
|
-
command: 'git add .',
|
|
45350
|
-
cwd: projectPath,
|
|
45351
|
-
env: agentEnv,
|
|
45352
|
-
});
|
|
45458
|
+
await stageCommitChanges(projectPath, agentEnv, options === null || options === void 0 ? void 0 : options.excludePaths);
|
|
45353
45459
|
await runGitCommand({
|
|
45354
45460
|
command: buildGitCommitCommand(commitMessagePath, signingFlag),
|
|
45355
45461
|
cwd: projectPath,
|
|
@@ -45363,6 +45469,56 @@ async function commitChanges(message, options) {
|
|
|
45363
45469
|
await unlink(commitMessagePath).catch(() => undefined);
|
|
45364
45470
|
}
|
|
45365
45471
|
}
|
|
45472
|
+
/**
|
|
45473
|
+
* Stages repository changes and optionally unstages temporary files that should not end up inside the commit.
|
|
45474
|
+
*/
|
|
45475
|
+
async function stageCommitChanges(projectPath, agentEnv, excludePaths) {
|
|
45476
|
+
await runGitCommand({
|
|
45477
|
+
command: 'git add .',
|
|
45478
|
+
cwd: projectPath,
|
|
45479
|
+
env: agentEnv,
|
|
45480
|
+
});
|
|
45481
|
+
const excludedGitPaths = normalizeExcludedGitPaths(projectPath, excludePaths);
|
|
45482
|
+
if (excludedGitPaths.length === 0) {
|
|
45483
|
+
return;
|
|
45484
|
+
}
|
|
45485
|
+
await runGitCommand({
|
|
45486
|
+
command: `git reset --quiet HEAD -- ${excludedGitPaths.map(quoteShellPath).join(' ')}`,
|
|
45487
|
+
cwd: projectPath,
|
|
45488
|
+
env: agentEnv,
|
|
45489
|
+
isVerbose: false,
|
|
45490
|
+
});
|
|
45491
|
+
}
|
|
45492
|
+
/**
|
|
45493
|
+
* Converts excluded filesystem paths into unique repository-relative Git paths.
|
|
45494
|
+
*/
|
|
45495
|
+
function normalizeExcludedGitPaths(projectPath, excludePaths) {
|
|
45496
|
+
if (!excludePaths || excludePaths.length === 0) {
|
|
45497
|
+
return [];
|
|
45498
|
+
}
|
|
45499
|
+
return [
|
|
45500
|
+
...new Set(excludePaths
|
|
45501
|
+
.map((excludePath) => normalizeExcludedGitPath(projectPath, excludePath))
|
|
45502
|
+
.filter((gitPath) => Boolean(gitPath))),
|
|
45503
|
+
];
|
|
45504
|
+
}
|
|
45505
|
+
/**
|
|
45506
|
+
* Converts one excluded filesystem path into a Git-friendly repository-relative path.
|
|
45507
|
+
*/
|
|
45508
|
+
function normalizeExcludedGitPath(projectPath, excludePath) {
|
|
45509
|
+
const absoluteExcludePath = resolve(projectPath, excludePath);
|
|
45510
|
+
const relativeExcludePath = relative(projectPath, absoluteExcludePath).replace(/\\/gu, '/');
|
|
45511
|
+
if (relativeExcludePath === '' || relativeExcludePath === '.' || relativeExcludePath.startsWith('../')) {
|
|
45512
|
+
return undefined;
|
|
45513
|
+
}
|
|
45514
|
+
return relativeExcludePath;
|
|
45515
|
+
}
|
|
45516
|
+
/**
|
|
45517
|
+
* Quotes one Git path for safe shell execution.
|
|
45518
|
+
*/
|
|
45519
|
+
function quoteShellPath(path) {
|
|
45520
|
+
return JSON.stringify(path);
|
|
45521
|
+
}
|
|
45366
45522
|
/**
|
|
45367
45523
|
* Branded error used when pushing committed changes fails.
|
|
45368
45524
|
*/
|
|
@@ -46737,6 +46893,15 @@ function buildPromptLabelForDisplay(file, section) {
|
|
|
46737
46893
|
return `${relative(process.cwd(), file.path).replace(/\\/g, '/')}#${section.startLine + 1}`;
|
|
46738
46894
|
}
|
|
46739
46895
|
|
|
46896
|
+
/**
|
|
46897
|
+
* Extracts a short summary line from a prompt section.
|
|
46898
|
+
*/
|
|
46899
|
+
function buildPromptSummary(file, section) {
|
|
46900
|
+
const lines = buildCodexPrompt(file, section).split(/\r?\n/);
|
|
46901
|
+
const firstLine = lines.find((line) => line.trim() !== '');
|
|
46902
|
+
return (firstLine === null || firstLine === void 0 ? void 0 : firstLine.trim()) || '(empty prompt)';
|
|
46903
|
+
}
|
|
46904
|
+
|
|
46740
46905
|
/**
|
|
46741
46906
|
* Builds the script path for a prompt section.
|
|
46742
46907
|
*/
|
|
@@ -46796,15 +46961,6 @@ function findNextTodoPrompt(files, minimumPriority = 0) {
|
|
|
46796
46961
|
return nextPrompt;
|
|
46797
46962
|
}
|
|
46798
46963
|
|
|
46799
|
-
/**
|
|
46800
|
-
* Extracts a short summary line from a prompt section.
|
|
46801
|
-
*/
|
|
46802
|
-
function buildPromptSummary(file, section) {
|
|
46803
|
-
const lines = buildCodexPrompt(file, section).split(/\r?\n/);
|
|
46804
|
-
const firstLine = lines.find((line) => line.trim() !== '');
|
|
46805
|
-
return (firstLine === null || firstLine === void 0 ? void 0 : firstLine.trim()) || '(empty prompt)';
|
|
46806
|
-
}
|
|
46807
|
-
|
|
46808
46964
|
/**
|
|
46809
46965
|
* Lists upcoming tasks that are ready to run (no authoring placeholders).
|
|
46810
46966
|
*/
|
|
@@ -47356,25 +47512,29 @@ async function runBashScriptWithOutput(options) {
|
|
|
47356
47512
|
}
|
|
47357
47513
|
|
|
47358
47514
|
/**
|
|
47359
|
-
* Creates a temporary script file, runs a handler, and
|
|
47515
|
+
* Creates a temporary script file, runs a handler, and cleans it up unless preservation is requested or the run fails.
|
|
47360
47516
|
*/
|
|
47361
47517
|
async function withTempScript(options, handler) {
|
|
47362
|
-
const { scriptPath, scriptContent
|
|
47518
|
+
const { scriptPath, scriptContent } = options;
|
|
47519
|
+
let hasFailed = false;
|
|
47363
47520
|
await mkdir(dirname$1(scriptPath), { recursive: true });
|
|
47364
47521
|
await writeFile(scriptPath, scriptContent, 'utf-8');
|
|
47365
|
-
promptRoundArtifacts === null || promptRoundArtifacts === void 0 ? void 0 : promptRoundArtifacts.track(scriptPath, getPromptRoundArtifactKindFromScriptPath(scriptPath));
|
|
47366
47522
|
try {
|
|
47367
47523
|
return await handler(scriptPath);
|
|
47368
47524
|
}
|
|
47525
|
+
catch (error) {
|
|
47526
|
+
hasFailed = true;
|
|
47527
|
+
throw error;
|
|
47528
|
+
}
|
|
47369
47529
|
finally {
|
|
47370
|
-
if (
|
|
47530
|
+
if (shouldDeleteTemporaryArtifact({ preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess, hasFailed })) {
|
|
47371
47531
|
await unlink(scriptPath).catch(() => undefined);
|
|
47372
47532
|
}
|
|
47373
47533
|
}
|
|
47374
47534
|
}
|
|
47375
47535
|
|
|
47376
47536
|
/**
|
|
47377
|
-
* Creates a temporary script file, runs it, captures output, and cleans it up
|
|
47537
|
+
* Creates a temporary script file, runs it, captures output, and cleans it up unless preservation is requested or the run fails.
|
|
47378
47538
|
*/
|
|
47379
47539
|
async function $runGoScriptWithOutput(options) {
|
|
47380
47540
|
return await withTempScript(options, async (scriptPath) => {
|
|
@@ -47477,7 +47637,7 @@ class ClaudeCodeRunner {
|
|
|
47477
47637
|
scriptPath: options.scriptPath,
|
|
47478
47638
|
scriptContent,
|
|
47479
47639
|
logPath: options.logPath,
|
|
47480
|
-
|
|
47640
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47481
47641
|
});
|
|
47482
47642
|
const usage = parseClaudeCodeJsonOutput(output);
|
|
47483
47643
|
return { usage };
|
|
@@ -47485,7 +47645,7 @@ class ClaudeCodeRunner {
|
|
|
47485
47645
|
}
|
|
47486
47646
|
|
|
47487
47647
|
/**
|
|
47488
|
-
* Creates a temporary script file, runs it, and cleans it up
|
|
47648
|
+
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
47489
47649
|
*/
|
|
47490
47650
|
async function $runGoScript(options) {
|
|
47491
47651
|
await withTempScript(options, async (scriptPath) => {
|
|
@@ -47541,7 +47701,7 @@ class ClineRunner {
|
|
|
47541
47701
|
scriptPath: options.scriptPath,
|
|
47542
47702
|
scriptContent,
|
|
47543
47703
|
logPath: options.logPath,
|
|
47544
|
-
|
|
47704
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47545
47705
|
});
|
|
47546
47706
|
return { usage: UNCERTAIN_USAGE };
|
|
47547
47707
|
}
|
|
@@ -47666,7 +47826,7 @@ class GeminiRunner {
|
|
|
47666
47826
|
scriptPath: options.scriptPath,
|
|
47667
47827
|
scriptContent,
|
|
47668
47828
|
logPath: options.logPath,
|
|
47669
|
-
|
|
47829
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47670
47830
|
});
|
|
47671
47831
|
const usage = parseGeminiUsageFromOutput(output, options.prompt, this.options.model);
|
|
47672
47832
|
return { usage };
|
|
@@ -47723,7 +47883,7 @@ class GitHubCopilotRunner {
|
|
|
47723
47883
|
scriptPath: options.scriptPath,
|
|
47724
47884
|
scriptContent,
|
|
47725
47885
|
logPath: options.logPath,
|
|
47726
|
-
|
|
47886
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47727
47887
|
});
|
|
47728
47888
|
return { usage: UNCERTAIN_USAGE };
|
|
47729
47889
|
}
|
|
@@ -47899,7 +48059,7 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
47899
48059
|
}
|
|
47900
48060
|
|
|
47901
48061
|
/**
|
|
47902
|
-
* Creates a temporary script file, runs it, waits for a completion marker and idle time, and
|
|
48062
|
+
* 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.
|
|
47903
48063
|
* Returns the captured output for post-processing.
|
|
47904
48064
|
*/
|
|
47905
48065
|
async function $runGoScriptUntilMarkerIdle(options) {
|
|
@@ -48288,7 +48448,7 @@ class OpenAiCodexRunner {
|
|
|
48288
48448
|
completionLineMatcher: CODEX_COMPLETION_LINE,
|
|
48289
48449
|
idleTimeoutMs: CODEX_COMPLETION_IDLE_MS,
|
|
48290
48450
|
logPath: options.logPath,
|
|
48291
|
-
|
|
48451
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48292
48452
|
});
|
|
48293
48453
|
this.rateLimitBackoff.reset();
|
|
48294
48454
|
return { usage: buildCodexUsageFromOutput(output, this.options.model) };
|
|
@@ -48423,7 +48583,7 @@ class OpencodeRunner {
|
|
|
48423
48583
|
scriptPath: options.scriptPath,
|
|
48424
48584
|
scriptContent,
|
|
48425
48585
|
logPath: options.logPath,
|
|
48426
|
-
|
|
48586
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48427
48587
|
});
|
|
48428
48588
|
}
|
|
48429
48589
|
catch (error) {
|
|
@@ -48451,6 +48611,7 @@ async function runPromptTestCommand(options) {
|
|
|
48451
48611
|
${options.command}
|
|
48452
48612
|
`),
|
|
48453
48613
|
logPath: options.logPath,
|
|
48614
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48454
48615
|
});
|
|
48455
48616
|
}
|
|
48456
48617
|
|
|
@@ -48475,7 +48636,7 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48475
48636
|
scriptPath: options.scriptPath,
|
|
48476
48637
|
projectPath: options.projectPath,
|
|
48477
48638
|
logPath: options.logPath,
|
|
48478
|
-
|
|
48639
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48479
48640
|
});
|
|
48480
48641
|
return { ...result, attemptCount: 1 };
|
|
48481
48642
|
}
|
|
@@ -48488,7 +48649,7 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48488
48649
|
scriptPath: options.scriptPath,
|
|
48489
48650
|
projectPath: options.projectPath,
|
|
48490
48651
|
logPath: options.logPath,
|
|
48491
|
-
|
|
48652
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48492
48653
|
});
|
|
48493
48654
|
console.info(colors.gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
|
|
48494
48655
|
try {
|
|
@@ -48497,6 +48658,7 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48497
48658
|
projectPath: options.projectPath,
|
|
48498
48659
|
scriptPath: buildPromptTestScriptPath(options.scriptPath),
|
|
48499
48660
|
logPath: options.logPath,
|
|
48661
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48500
48662
|
});
|
|
48501
48663
|
return { ...result, attemptCount };
|
|
48502
48664
|
}
|
|
@@ -48578,24 +48740,213 @@ function buildPromptTestScriptPath(scriptPath) {
|
|
|
48578
48740
|
}
|
|
48579
48741
|
|
|
48580
48742
|
/**
|
|
48581
|
-
* Maximum number of
|
|
48582
|
-
*
|
|
48583
|
-
* @private internal constant of coder run UI
|
|
48743
|
+
* Maximum number of output lines reserved for agent output in the UI.
|
|
48584
48744
|
*/
|
|
48585
|
-
const
|
|
48745
|
+
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48586
48746
|
/**
|
|
48587
|
-
*
|
|
48747
|
+
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
48748
|
+
*/
|
|
48749
|
+
function buildCoderRunUiFrame(options) {
|
|
48750
|
+
const totalWidth = Math.max(56, Math.min(options.terminalWidth, 96));
|
|
48751
|
+
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
48752
|
+
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
48753
|
+
const sessionScopeLine = options.progress.sessionTotal > 0
|
|
48754
|
+
? `Working on ${options.progress.currentPromptIndex}/${options.progress.sessionTotal} prompts with Priority ≥${options.config.priority}`
|
|
48755
|
+
: `No runnable prompts with Priority ≥${options.config.priority}`;
|
|
48756
|
+
const sessionCountLine = `Done ${options.progress.sessionDone}/${options.progress.sessionTotal} this run · Repo total ${options.progress.totalPrompts}`;
|
|
48757
|
+
const sessionQueueParts = [];
|
|
48758
|
+
if (options.progress.skippedPrompts > 0) {
|
|
48759
|
+
sessionQueueParts.push(`Skipping ${formatPromptCount(options.progress.skippedPrompts)} with Priority <${options.config.priority}`);
|
|
48760
|
+
}
|
|
48761
|
+
if (options.progress.toBeWrittenPrompts > 0) {
|
|
48762
|
+
sessionQueueParts.push(`Write first ${formatPromptCount(options.progress.toBeWrittenPrompts)}`);
|
|
48763
|
+
}
|
|
48764
|
+
const sessionLines = [
|
|
48765
|
+
`${buildPhaseBadge(options.phase, options.pauseState)} ${fitPlainText(options.statusMessage, totalWidth - 18)}`,
|
|
48766
|
+
sessionScopeLine,
|
|
48767
|
+
sessionCountLine,
|
|
48768
|
+
...(sessionQueueParts.length > 0 ? [sessionQueueParts.join(' · ')] : []),
|
|
48769
|
+
`Elapsed ${options.progress.elapsedText} · Est. total ${options.progress.estimatedTotalText} · Est. done ${options.progress.estimatedLabel}`,
|
|
48770
|
+
buildProgressBar(options.progress.percentage, totalWidth - 6, `${options.progress.percentage}% complete (${options.progress.sessionDone}/${options.progress.sessionTotal} done)`),
|
|
48771
|
+
];
|
|
48772
|
+
const metadataParts = [options.config.agentName || 'No agent selected'];
|
|
48773
|
+
if (options.config.modelName) {
|
|
48774
|
+
metadataParts.push(options.config.modelName);
|
|
48775
|
+
}
|
|
48776
|
+
if (options.config.thinkingLevel) {
|
|
48777
|
+
metadataParts.push(`thinking ${options.config.thinkingLevel}`);
|
|
48778
|
+
}
|
|
48779
|
+
const runnerDetails = [
|
|
48780
|
+
[`${colors.bgCyan.black(' PTBK ')}`, colors.bgBlue.white(' CODER '), colors.bold.white(' Promptbook Coder')]
|
|
48781
|
+
.join(''),
|
|
48782
|
+
metadataParts.join(' · '),
|
|
48783
|
+
buildConfigSummaryLine(options.config),
|
|
48784
|
+
];
|
|
48785
|
+
const currentTaskLines = options.currentPromptLabel
|
|
48786
|
+
? [
|
|
48787
|
+
`${promptStatusPrefix}${colors.bold.white(fitPlainText(options.currentPromptLabel, totalWidth - 8))}`,
|
|
48788
|
+
`Attempt ${options.currentAttempt}/${options.maxAttempts} · ${options.statusMessage}`,
|
|
48789
|
+
...options.detailLines.map((detailLine) => `• ${detailLine}`),
|
|
48790
|
+
]
|
|
48791
|
+
: [options.statusMessage, ...options.detailLines.map((detailLine) => `• ${detailLine}`)];
|
|
48792
|
+
const visibleOutputLines = buildVisibleOutputLines(options.agentOutputLines);
|
|
48793
|
+
const controls = buildControlPills(options.pauseState, options.pendingEnterLabel).join(' ');
|
|
48794
|
+
const frame = [
|
|
48795
|
+
...renderBox('Brand', runnerDetails, totalWidth, colors.cyan.bold),
|
|
48796
|
+
...renderBox('Session', sessionLines, totalWidth, colors.yellow.bold),
|
|
48797
|
+
...renderBox(options.currentPromptLabel ? 'Current task' : 'Queue', currentTaskLines, totalWidth, colors.magenta.bold),
|
|
48798
|
+
...renderBox('Live output', visibleOutputLines, totalWidth, colors.green.bold),
|
|
48799
|
+
];
|
|
48800
|
+
if (options.errors.length > 0) {
|
|
48801
|
+
frame.push(...renderBox('Errors', options.errors.map((errorLine) => `${colors.red('✗')} ${errorLine}`), totalWidth, colors.red.bold));
|
|
48802
|
+
}
|
|
48803
|
+
frame.push(...renderBox('Controls', [controls], totalWidth, colors.white.bold));
|
|
48804
|
+
return frame;
|
|
48805
|
+
}
|
|
48806
|
+
/**
|
|
48807
|
+
* Builds the fixed-height live output section so streaming updates do not keep resizing the frame.
|
|
48808
|
+
*/
|
|
48809
|
+
function buildVisibleOutputLines(agentOutputLines) {
|
|
48810
|
+
const visibleOutputLines = agentOutputLines.length > 0
|
|
48811
|
+
? agentOutputLines.slice(-MAX_VISIBLE_OUTPUT_LINES).map((line) => `› ${stripAnsi(line)}`)
|
|
48812
|
+
: ['No live agent output yet.'];
|
|
48813
|
+
while (visibleOutputLines.length < MAX_VISIBLE_OUTPUT_LINES) {
|
|
48814
|
+
visibleOutputLines.push('');
|
|
48815
|
+
}
|
|
48816
|
+
return visibleOutputLines;
|
|
48817
|
+
}
|
|
48818
|
+
/**
|
|
48819
|
+
* Renders a framed box with a colored title and padded body lines.
|
|
48820
|
+
*/
|
|
48821
|
+
function renderBox(title, lines, totalWidth, colorizeTitle) {
|
|
48822
|
+
const bodyWidth = Math.max(10, totalWidth - 4);
|
|
48823
|
+
const titleText = ` ${title} `;
|
|
48824
|
+
const topBorder = colors.gray('┌') +
|
|
48825
|
+
colorizeTitle(titleText) +
|
|
48826
|
+
colors.gray('─'.repeat(Math.max(0, totalWidth - 2 - titleText.length)) + '┐');
|
|
48827
|
+
const body = lines.map((line) => {
|
|
48828
|
+
const paddedLine = padAnsiText(line, bodyWidth);
|
|
48829
|
+
return colors.gray('│ ') + paddedLine + colors.gray(' │');
|
|
48830
|
+
});
|
|
48831
|
+
const bottomBorder = colors.gray(`└${'─'.repeat(totalWidth - 2)}┘`);
|
|
48832
|
+
return [topBorder, ...body, bottomBorder];
|
|
48833
|
+
}
|
|
48834
|
+
/**
|
|
48835
|
+
* Builds the compact config summary line shown in the branding box.
|
|
48836
|
+
*/
|
|
48837
|
+
function buildConfigSummaryLine(config) {
|
|
48838
|
+
const parts = [`Priority ≥${config.priority}`];
|
|
48839
|
+
if (config.context) {
|
|
48840
|
+
parts.unshift(`Context ${config.context}`);
|
|
48841
|
+
}
|
|
48842
|
+
if (config.testCommand) {
|
|
48843
|
+
parts.push(`Test ${config.testCommand}`);
|
|
48844
|
+
}
|
|
48845
|
+
return parts.join(' · ');
|
|
48846
|
+
}
|
|
48847
|
+
/**
|
|
48848
|
+
* Builds the colored phase badge shown in the session box.
|
|
48849
|
+
*/
|
|
48850
|
+
function buildPhaseBadge(phase, pauseState) {
|
|
48851
|
+
if (pauseState !== 'RUNNING' || phase === 'paused') {
|
|
48852
|
+
return colors.bgYellow.black(' PAUSED ');
|
|
48853
|
+
}
|
|
48854
|
+
switch (phase) {
|
|
48855
|
+
case 'loading':
|
|
48856
|
+
case 'initializing':
|
|
48857
|
+
return colors.bgCyan.black(' LOADING ');
|
|
48858
|
+
case 'running':
|
|
48859
|
+
return colors.bgGreen.black(' RUNNING ');
|
|
48860
|
+
case 'verifying':
|
|
48861
|
+
return colors.bgMagenta.white(' VERIFYING ');
|
|
48862
|
+
case 'waiting':
|
|
48863
|
+
return colors.bgBlue.white(' WAITING ');
|
|
48864
|
+
case 'done':
|
|
48865
|
+
return colors.bgGreen.black(' DONE ');
|
|
48866
|
+
case 'error':
|
|
48867
|
+
return colors.bgRed.white(' ERROR ');
|
|
48868
|
+
default:
|
|
48869
|
+
return colors.bgWhite.black(' READY ');
|
|
48870
|
+
}
|
|
48871
|
+
}
|
|
48872
|
+
/**
|
|
48873
|
+
* Builds the progress bar shown in the session box.
|
|
48874
|
+
*/
|
|
48875
|
+
function buildProgressBar(percentage, availableWidth, label) {
|
|
48876
|
+
const percentageLabel = label;
|
|
48877
|
+
const barWidth = Math.max(10, availableWidth - percentageLabel.length - 1);
|
|
48878
|
+
const filledWidth = Math.round((percentage / 100) * barWidth);
|
|
48879
|
+
const emptyWidth = Math.max(0, barWidth - filledWidth);
|
|
48880
|
+
return `${colors.green('█'.repeat(filledWidth))}${colors.gray('░'.repeat(emptyWidth))} ${percentageLabel}`;
|
|
48881
|
+
}
|
|
48882
|
+
/**
|
|
48883
|
+
* Formats a prompt count with singular/plural wording.
|
|
48884
|
+
*/
|
|
48885
|
+
function formatPromptCount(count) {
|
|
48886
|
+
return `${count} prompt${count === 1 ? '' : 's'}`;
|
|
48887
|
+
}
|
|
48888
|
+
/**
|
|
48889
|
+
* Builds the control pills shown in the footer box.
|
|
48890
|
+
*/
|
|
48891
|
+
function buildControlPills(pauseState, pendingEnterLabel) {
|
|
48892
|
+
const pills = [];
|
|
48893
|
+
if (pendingEnterLabel) {
|
|
48894
|
+
pills.push(colors.bgWhite.black(' ENTER ') + colors.white(` ${pendingEnterLabel}`));
|
|
48895
|
+
}
|
|
48896
|
+
pills.push(pauseState === 'RUNNING'
|
|
48897
|
+
? colors.bgYellow.black(' P ') + colors.white(' Pause')
|
|
48898
|
+
: colors.bgYellow.black(' P ') + colors.white(' Resume'));
|
|
48899
|
+
pills.push(colors.bgRed.white(' CTRL+C ') + colors.white(' Exit'));
|
|
48900
|
+
return pills;
|
|
48901
|
+
}
|
|
48902
|
+
/**
|
|
48903
|
+
* Pads or truncates a possibly ANSI-colored line to the target visible width.
|
|
48904
|
+
*/
|
|
48905
|
+
function padAnsiText(text, width) {
|
|
48906
|
+
const fittedText = fitAnsiText(text, width);
|
|
48907
|
+
return fittedText + ' '.repeat(Math.max(0, width - visibleLength(fittedText)));
|
|
48908
|
+
}
|
|
48909
|
+
/**
|
|
48910
|
+
* Truncates a possibly ANSI-colored line to the target visible width.
|
|
48911
|
+
*/
|
|
48912
|
+
function fitAnsiText(text, width) {
|
|
48913
|
+
if (visibleLength(text) <= width) {
|
|
48914
|
+
return text;
|
|
48915
|
+
}
|
|
48916
|
+
return fitPlainText(stripAnsi(text), width);
|
|
48917
|
+
}
|
|
48918
|
+
/**
|
|
48919
|
+
* Truncates a plain-text line to the target width with an ellipsis.
|
|
48920
|
+
*/
|
|
48921
|
+
function fitPlainText(text, width) {
|
|
48922
|
+
if (text.length <= width) {
|
|
48923
|
+
return text;
|
|
48924
|
+
}
|
|
48925
|
+
if (width <= 3) {
|
|
48926
|
+
return '.'.repeat(width);
|
|
48927
|
+
}
|
|
48928
|
+
return `${text.slice(0, width - 3)}...`;
|
|
48929
|
+
}
|
|
48930
|
+
/**
|
|
48931
|
+
* Measures visible string width by stripping ANSI escape codes.
|
|
48932
|
+
*/
|
|
48933
|
+
function visibleLength(text) {
|
|
48934
|
+
return stripAnsi(text).length;
|
|
48935
|
+
}
|
|
48936
|
+
/**
|
|
48937
|
+
* Strips ANSI escape codes from a string.
|
|
48938
|
+
*/
|
|
48939
|
+
function stripAnsi(text) {
|
|
48940
|
+
// eslint-disable-next-line no-control-regex
|
|
48941
|
+
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48942
|
+
}
|
|
48943
|
+
|
|
48944
|
+
/**
|
|
48945
|
+
* Maximum number of agent output lines kept in the scrolling output area.
|
|
48588
48946
|
*
|
|
48589
48947
|
* @private internal constant of coder run UI
|
|
48590
48948
|
*/
|
|
48591
|
-
const
|
|
48592
|
-
sameDay: '[Today] h:mm',
|
|
48593
|
-
nextDay: '[Tomorrow] h:mm',
|
|
48594
|
-
nextWeek: 'dddd h:mm',
|
|
48595
|
-
lastDay: '[Yesterday] h:mm',
|
|
48596
|
-
lastWeek: 'dddd h:mm',
|
|
48597
|
-
sameElse: 'MMM D h:mm',
|
|
48598
|
-
};
|
|
48949
|
+
const MAX_AGENT_OUTPUT_LINES = 12;
|
|
48599
48950
|
/**
|
|
48600
48951
|
* Reactive state manager for the coder run terminal UI.
|
|
48601
48952
|
*
|
|
@@ -48611,35 +48962,27 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48611
48962
|
this.currentPromptLabel = '';
|
|
48612
48963
|
this.currentAttempt = 1;
|
|
48613
48964
|
this.maxAttempts = 3;
|
|
48965
|
+
this.detailLines = [];
|
|
48614
48966
|
this.agentOutputLines = [];
|
|
48615
48967
|
this.phase = 'initializing';
|
|
48616
48968
|
this.statusMessage = 'Initializing...';
|
|
48617
48969
|
this.errors = [];
|
|
48618
48970
|
this.stats = { done: 0, forAgent: 0, belowMinimumPriority: 0, toBeWritten: 0 };
|
|
48619
|
-
|
|
48620
|
-
* Total milliseconds the timer was paused/waiting (excluded from elapsed display).
|
|
48621
|
-
*/
|
|
48622
|
-
this.pausedMs = 0;
|
|
48623
|
-
this.startTime = startTime;
|
|
48624
|
-
// Timer starts paused — callers call `resumeTimer()` when actual work begins.
|
|
48625
|
-
this.pausedSince = startTime.clone();
|
|
48971
|
+
this.timer = new CoderRunTimer(startTime, true);
|
|
48626
48972
|
}
|
|
48627
48973
|
/**
|
|
48628
48974
|
* Pauses the elapsed timer (e.g. while waiting for user input or paused state).
|
|
48629
48975
|
*/
|
|
48630
48976
|
pauseTimer() {
|
|
48631
|
-
|
|
48632
|
-
|
|
48633
|
-
}
|
|
48977
|
+
this.timer.pause();
|
|
48978
|
+
this.emitChange();
|
|
48634
48979
|
}
|
|
48635
48980
|
/**
|
|
48636
48981
|
* Resumes the elapsed timer after a pause.
|
|
48637
48982
|
*/
|
|
48638
48983
|
resumeTimer() {
|
|
48639
|
-
|
|
48640
|
-
|
|
48641
|
-
this.pausedSince = undefined;
|
|
48642
|
-
}
|
|
48984
|
+
this.timer.resume();
|
|
48985
|
+
this.emitChange();
|
|
48643
48986
|
}
|
|
48644
48987
|
/**
|
|
48645
48988
|
* Replaces the configuration shown in the UI header.
|
|
@@ -48663,41 +49006,15 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48663
49006
|
*/
|
|
48664
49007
|
getProgress() {
|
|
48665
49008
|
var _a;
|
|
48666
|
-
|
|
48667
|
-
const totalPrompts = stats.done + stats.forAgent + stats.toBeWritten;
|
|
48668
|
-
const sessionDone = Math.max(0, stats.done - ((_a = this.initialDone) !== null && _a !== void 0 ? _a : stats.done));
|
|
48669
|
-
const sessionTotal = sessionDone + stats.forAgent;
|
|
48670
|
-
const percentage = totalPrompts > 0 ? Math.round((stats.done / totalPrompts) * 100) : 0;
|
|
48671
|
-
const wallMs = moment().diff(this.startTime);
|
|
48672
|
-
const currentPauseMs = this.pausedSince !== undefined ? moment().diff(this.pausedSince) : 0;
|
|
48673
|
-
const activeMs = Math.max(0, wallMs - this.pausedMs - currentPauseMs);
|
|
48674
|
-
const elapsedDuration = moment.duration(activeMs);
|
|
48675
|
-
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
48676
|
-
let estimatedTotalText = '\u2014';
|
|
48677
|
-
let estimatedLabel = 'unknown';
|
|
48678
|
-
if (totalPrompts > 0 && stats.done > 0) {
|
|
48679
|
-
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / stats.done;
|
|
48680
|
-
const estimatedRemainingMs = estimatedTotalMs - elapsedDuration.asMilliseconds();
|
|
48681
|
-
const estimatedTotalDuration = moment.duration(estimatedTotalMs);
|
|
48682
|
-
const estimatedCompletion = moment().add(estimatedRemainingMs, 'milliseconds');
|
|
48683
|
-
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
48684
|
-
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
48685
|
-
}
|
|
48686
|
-
return {
|
|
48687
|
-
totalPrompts,
|
|
48688
|
-
sessionDone,
|
|
48689
|
-
sessionTotal,
|
|
48690
|
-
percentage,
|
|
48691
|
-
elapsedText,
|
|
48692
|
-
estimatedTotalText,
|
|
48693
|
-
estimatedLabel,
|
|
48694
|
-
};
|
|
49009
|
+
return buildCoderRunProgressSnapshot(this.stats, this.timer.getElapsedDuration(), (_a = this.initialDone) !== null && _a !== void 0 ? _a : this.stats.done);
|
|
48695
49010
|
}
|
|
48696
49011
|
/**
|
|
48697
49012
|
* Sets the label of the prompt currently being processed and resets per-prompt state.
|
|
48698
49013
|
*/
|
|
48699
49014
|
setCurrentPrompt(label) {
|
|
48700
49015
|
this.currentPromptLabel = label;
|
|
49016
|
+
this.detailLines = [];
|
|
49017
|
+
this.pendingEnterLabel = undefined;
|
|
48701
49018
|
this.agentOutputLines = [];
|
|
48702
49019
|
this.currentAttempt = 1;
|
|
48703
49020
|
this.emitChange();
|
|
@@ -48737,6 +49054,20 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48737
49054
|
this.statusMessage = message;
|
|
48738
49055
|
this.emitChange();
|
|
48739
49056
|
}
|
|
49057
|
+
/**
|
|
49058
|
+
* Replaces the contextual detail lines shown beneath the current prompt status.
|
|
49059
|
+
*/
|
|
49060
|
+
setDetailLines(detailLines) {
|
|
49061
|
+
this.detailLines = detailLines.filter((detailLine) => detailLine.trim() !== '');
|
|
49062
|
+
this.emitChange();
|
|
49063
|
+
}
|
|
49064
|
+
/**
|
|
49065
|
+
* Sets or clears the Enter-key action label shown in the controls panel.
|
|
49066
|
+
*/
|
|
49067
|
+
setPendingEnterLabel(pendingEnterLabel) {
|
|
49068
|
+
this.pendingEnterLabel = pendingEnterLabel;
|
|
49069
|
+
this.emitChange();
|
|
49070
|
+
}
|
|
48740
49071
|
/**
|
|
48741
49072
|
* Appends an error message to the error list shown in the UI.
|
|
48742
49073
|
*/
|
|
@@ -48748,50 +49079,35 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48748
49079
|
this.emit('change');
|
|
48749
49080
|
}
|
|
48750
49081
|
}
|
|
48751
|
-
/**
|
|
48752
|
-
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
48753
|
-
*
|
|
48754
|
-
* @private internal utility of coder run UI
|
|
48755
|
-
*/
|
|
48756
|
-
function formatDurationBrief(duration) {
|
|
48757
|
-
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
48758
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
48759
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
48760
|
-
const seconds = totalSeconds % 60;
|
|
48761
|
-
const parts = [];
|
|
48762
|
-
if (hours > 0) {
|
|
48763
|
-
parts.push(`${hours}h`);
|
|
48764
|
-
}
|
|
48765
|
-
if (minutes > 0) {
|
|
48766
|
-
parts.push(`${minutes}m`);
|
|
48767
|
-
}
|
|
48768
|
-
if (!parts.length && seconds > 0) {
|
|
48769
|
-
parts.push(`${seconds}s`);
|
|
48770
|
-
}
|
|
48771
|
-
if (!parts.length) {
|
|
48772
|
-
parts.push('0s');
|
|
48773
|
-
}
|
|
48774
|
-
return parts.join(' ');
|
|
48775
|
-
}
|
|
48776
49082
|
|
|
48777
49083
|
/**
|
|
48778
|
-
* Refresh
|
|
49084
|
+
* Refresh cadence used only while the rich coder UI needs animated updates.
|
|
48779
49085
|
*
|
|
48780
49086
|
* @private internal constant of coder run UI
|
|
48781
49087
|
*/
|
|
48782
|
-
const
|
|
49088
|
+
const ACTIVE_CODER_RUN_UI_REFRESH_INTERVAL_MS = 1000;
|
|
48783
49089
|
/**
|
|
48784
|
-
*
|
|
49090
|
+
* Phases that still benefit from automatic refreshes because the frame can change
|
|
49091
|
+
* over time even without new runner output.
|
|
48785
49092
|
*
|
|
48786
49093
|
* @private internal constant of coder run UI
|
|
48787
49094
|
*/
|
|
48788
|
-
const
|
|
49095
|
+
const AUTO_REFRESH_PHASES = ['initializing', 'loading', 'running', 'verifying'];
|
|
48789
49096
|
/**
|
|
48790
|
-
*
|
|
49097
|
+
* Returns the automatic refresh interval for the current UI state.
|
|
48791
49098
|
*
|
|
48792
|
-
*
|
|
49099
|
+
* Waiting, paused, and completed states return `undefined` so the rich UI stays
|
|
49100
|
+
* perfectly still until actual state changes arrive.
|
|
49101
|
+
*
|
|
49102
|
+
* @private internal utility of coder run UI
|
|
48793
49103
|
*/
|
|
48794
|
-
|
|
49104
|
+
function getCoderRunUiAutoRefreshInterval(phase, pauseState) {
|
|
49105
|
+
if (pauseState !== 'RUNNING') {
|
|
49106
|
+
return undefined;
|
|
49107
|
+
}
|
|
49108
|
+
return AUTO_REFRESH_PHASES.includes(phase) ? ACTIVE_CODER_RUN_UI_REFRESH_INTERVAL_MS : undefined;
|
|
49109
|
+
}
|
|
49110
|
+
|
|
48795
49111
|
/**
|
|
48796
49112
|
* Spinner animation frames.
|
|
48797
49113
|
*
|
|
@@ -48810,38 +49126,20 @@ const SPINNER_FRAMES = [
|
|
|
48810
49126
|
'\u280F',
|
|
48811
49127
|
];
|
|
48812
49128
|
/**
|
|
48813
|
-
*
|
|
48814
|
-
*
|
|
48815
|
-
* @private internal utility of coder run UI
|
|
48816
|
-
*/
|
|
48817
|
-
function stripAnsi(text) {
|
|
48818
|
-
// eslint-disable-next-line no-control-regex
|
|
48819
|
-
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48820
|
-
}
|
|
48821
|
-
/**
|
|
48822
|
-
* Returns the usable terminal width, capped at 80.
|
|
49129
|
+
* Returns the usable terminal width, capped at 96.
|
|
48823
49130
|
*
|
|
48824
49131
|
* @private internal utility of coder run UI
|
|
48825
49132
|
*/
|
|
48826
49133
|
function getTerminalWidth() {
|
|
48827
|
-
return Math.min(process.stdout.columns || 80,
|
|
48828
|
-
}
|
|
48829
|
-
/**
|
|
48830
|
-
* Builds a text progress bar string from a percentage.
|
|
48831
|
-
*
|
|
48832
|
-
* @private internal utility of coder run UI
|
|
48833
|
-
*/
|
|
48834
|
-
function buildProgressBar(percentage) {
|
|
48835
|
-
const filled = Math.round((percentage / 100) * PROGRESS_BAR_WIDTH);
|
|
48836
|
-
const empty = PROGRESS_BAR_WIDTH - filled;
|
|
48837
|
-
return colors.green('\u2588'.repeat(filled)) + colors.gray('\u2591'.repeat(empty)) + ` ${percentage}%`;
|
|
49134
|
+
return Math.min(process.stdout.columns || 80, 96);
|
|
48838
49135
|
}
|
|
48839
49136
|
/**
|
|
48840
49137
|
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
48841
49138
|
*
|
|
48842
|
-
* The UI reserves a fixed number of terminal lines and
|
|
48843
|
-
*
|
|
48844
|
-
*
|
|
49139
|
+
* The UI reserves a fixed number of terminal lines and refreshes them incrementally.
|
|
49140
|
+
* While a prompt is actively running, it schedules lightweight timed refreshes for
|
|
49141
|
+
* the spinner/progress area; otherwise it redraws only when real state changes arrive.
|
|
49142
|
+
* Any console output from runners is captured and fed into the scrolling agent-output area.
|
|
48845
49143
|
*
|
|
48846
49144
|
* On non-interactive (non-TTY) terminals the UI is skipped entirely and
|
|
48847
49145
|
* only the state object is provided.
|
|
@@ -48855,21 +49153,20 @@ function renderCoderRunUi(startTime) {
|
|
|
48855
49153
|
state,
|
|
48856
49154
|
startCapturingAgentOutput: () => { },
|
|
48857
49155
|
stopCapturingAgentOutput: () => { },
|
|
49156
|
+
waitForEnter: async () => { },
|
|
48858
49157
|
cleanup: () => { },
|
|
48859
49158
|
};
|
|
48860
49159
|
}
|
|
48861
|
-
// --- Console interception ---
|
|
48862
49160
|
const originalConsoleInfo = console.info;
|
|
48863
49161
|
const originalConsoleWarn = console.warn;
|
|
48864
49162
|
const originalConsoleError = console.error;
|
|
48865
49163
|
const originalConsoleLog = console.log;
|
|
48866
49164
|
let isCapturing = false;
|
|
49165
|
+
let pendingEnterResolver;
|
|
48867
49166
|
console.info = (...args) => {
|
|
48868
49167
|
if (isCapturing) {
|
|
48869
49168
|
state.addAgentOutput(args.map(String).join(' '));
|
|
48870
49169
|
}
|
|
48871
|
-
// In UI mode, non-captured output is intentionally suppressed
|
|
48872
|
-
// so it does not interfere with the repainted frame.
|
|
48873
49170
|
};
|
|
48874
49171
|
console.warn = (...args) => {
|
|
48875
49172
|
if (isCapturing) {
|
|
@@ -48886,192 +49183,205 @@ function renderCoderRunUi(startTime) {
|
|
|
48886
49183
|
state.addAgentOutput(args.map(String).join(' '));
|
|
48887
49184
|
}
|
|
48888
49185
|
};
|
|
48889
|
-
// --- Keyboard input (pause) ---
|
|
48890
49186
|
const readline = require('readline');
|
|
48891
49187
|
readline.emitKeypressEvents(process.stdin);
|
|
48892
49188
|
if (process.stdin.isTTY) {
|
|
48893
49189
|
process.stdin.setRawMode(true);
|
|
48894
49190
|
}
|
|
48895
|
-
const keypressHandler = (_str, key) => {
|
|
48896
|
-
if (key.ctrl && key.name === 'c') {
|
|
48897
|
-
cleanup();
|
|
48898
|
-
process.exit(0);
|
|
48899
|
-
}
|
|
48900
|
-
if (key.name === 'p') {
|
|
48901
|
-
const current = getPauseState();
|
|
48902
|
-
if (current === 'RUNNING') {
|
|
48903
|
-
requestPause();
|
|
48904
|
-
}
|
|
48905
|
-
else {
|
|
48906
|
-
requestResume();
|
|
48907
|
-
}
|
|
48908
|
-
}
|
|
48909
|
-
};
|
|
48910
|
-
process.stdin.on('keypress', keypressHandler);
|
|
48911
|
-
// --- Rendering ---
|
|
48912
49191
|
let spinnerFrame = 0;
|
|
48913
|
-
let
|
|
49192
|
+
let previousFrameLines = [];
|
|
48914
49193
|
let isRendering = false;
|
|
48915
49194
|
let renderScheduled = false;
|
|
49195
|
+
let autoRefreshTimeout;
|
|
49196
|
+
let isDisposed = false;
|
|
48916
49197
|
/**
|
|
48917
49198
|
* Schedules a render on the next tick if one isn't already pending.
|
|
48918
49199
|
* Prevents overlapping renders that cause cursor desync.
|
|
48919
49200
|
*/
|
|
48920
49201
|
function scheduleRender() {
|
|
48921
|
-
if (renderScheduled) {
|
|
49202
|
+
if (renderScheduled || isDisposed) {
|
|
48922
49203
|
return;
|
|
48923
49204
|
}
|
|
48924
49205
|
renderScheduled = true;
|
|
48925
49206
|
setImmediate(() => {
|
|
48926
49207
|
renderScheduled = false;
|
|
49208
|
+
if (isDisposed) {
|
|
49209
|
+
return;
|
|
49210
|
+
}
|
|
48927
49211
|
render();
|
|
48928
49212
|
});
|
|
48929
49213
|
}
|
|
48930
49214
|
/**
|
|
48931
|
-
*
|
|
49215
|
+
* Re-schedules automatic animation refreshes only while the frame can change by itself.
|
|
48932
49216
|
*/
|
|
48933
|
-
function
|
|
48934
|
-
if (
|
|
49217
|
+
function scheduleAutoRefresh() {
|
|
49218
|
+
if (autoRefreshTimeout) {
|
|
49219
|
+
clearTimeout(autoRefreshTimeout);
|
|
49220
|
+
autoRefreshTimeout = undefined;
|
|
49221
|
+
}
|
|
49222
|
+
const autoRefreshInterval = getCoderRunUiAutoRefreshInterval(state.phase, getPauseState());
|
|
49223
|
+
if (autoRefreshInterval === undefined) {
|
|
49224
|
+
return;
|
|
49225
|
+
}
|
|
49226
|
+
autoRefreshTimeout = setTimeout(() => {
|
|
49227
|
+
autoRefreshTimeout = undefined;
|
|
49228
|
+
scheduleRender();
|
|
49229
|
+
}, autoRefreshInterval);
|
|
49230
|
+
}
|
|
49231
|
+
/**
|
|
49232
|
+
* Moves the cursor relative to the bottom of the current frame and rewrites one line in place.
|
|
49233
|
+
*/
|
|
49234
|
+
function rewriteFrameLine(frameLineCount, lineIndex, line) {
|
|
49235
|
+
const linesUpFromBottom = Math.max(0, frameLineCount - 1 - lineIndex);
|
|
49236
|
+
if (linesUpFromBottom > 0) {
|
|
49237
|
+
process.stdout.write(`\x1b[${linesUpFromBottom}A`);
|
|
49238
|
+
}
|
|
49239
|
+
clearLine(process.stdout, 0);
|
|
49240
|
+
cursorTo(process.stdout, 0);
|
|
49241
|
+
process.stdout.write(line);
|
|
49242
|
+
cursorTo(process.stdout, 0);
|
|
49243
|
+
if (linesUpFromBottom > 0) {
|
|
49244
|
+
process.stdout.write(`\x1b[${linesUpFromBottom}B`);
|
|
49245
|
+
cursorTo(process.stdout, 0);
|
|
49246
|
+
}
|
|
49247
|
+
}
|
|
49248
|
+
/**
|
|
49249
|
+
* Fully rewrites the reserved frame area.
|
|
49250
|
+
*/
|
|
49251
|
+
function renderFullFrame(lines) {
|
|
49252
|
+
var _a;
|
|
49253
|
+
const previousFrameLineCount = previousFrameLines.length;
|
|
49254
|
+
const linesToRewriteCount = Math.max(previousFrameLineCount, lines.length);
|
|
49255
|
+
if (previousFrameLineCount > 1) {
|
|
49256
|
+
process.stdout.write(`\x1b[${previousFrameLineCount - 1}A`);
|
|
49257
|
+
}
|
|
49258
|
+
for (let i = 0; i < linesToRewriteCount; i++) {
|
|
49259
|
+
clearLine(process.stdout, 0);
|
|
49260
|
+
cursorTo(process.stdout, 0);
|
|
49261
|
+
process.stdout.write((_a = lines[i]) !== null && _a !== void 0 ? _a : '');
|
|
49262
|
+
if (i < linesToRewriteCount - 1) {
|
|
49263
|
+
process.stdout.write('\n');
|
|
49264
|
+
}
|
|
49265
|
+
}
|
|
49266
|
+
const clearedTrailingLines = linesToRewriteCount - lines.length;
|
|
49267
|
+
if (clearedTrailingLines > 0) {
|
|
49268
|
+
process.stdout.write(`\x1b[${clearedTrailingLines}A`);
|
|
49269
|
+
}
|
|
49270
|
+
cursorTo(process.stdout, 0);
|
|
49271
|
+
}
|
|
49272
|
+
/**
|
|
49273
|
+
* Updates only the frame rows whose visible content changed.
|
|
49274
|
+
*/
|
|
49275
|
+
function renderChangedLines(lines) {
|
|
49276
|
+
for (let i = 0; i < lines.length; i++) {
|
|
49277
|
+
if (previousFrameLines[i] === lines[i]) {
|
|
49278
|
+
continue;
|
|
49279
|
+
}
|
|
49280
|
+
rewriteFrameLine(lines.length, i, lines[i]);
|
|
49281
|
+
}
|
|
49282
|
+
}
|
|
49283
|
+
/**
|
|
49284
|
+
* Builds the current frame snapshot from the latest state.
|
|
49285
|
+
*/
|
|
49286
|
+
function buildFrameLines() {
|
|
49287
|
+
return buildCoderRunUiFrame({
|
|
49288
|
+
terminalWidth: getTerminalWidth(),
|
|
49289
|
+
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
49290
|
+
pauseState: getPauseState(),
|
|
49291
|
+
config: state.config,
|
|
49292
|
+
phase: state.phase,
|
|
49293
|
+
currentPromptLabel: state.currentPromptLabel,
|
|
49294
|
+
currentAttempt: state.currentAttempt,
|
|
49295
|
+
maxAttempts: state.maxAttempts,
|
|
49296
|
+
statusMessage: state.statusMessage,
|
|
49297
|
+
detailLines: state.detailLines,
|
|
49298
|
+
pendingEnterLabel: state.pendingEnterLabel,
|
|
49299
|
+
agentOutputLines: state.agentOutputLines,
|
|
49300
|
+
errors: state.errors,
|
|
49301
|
+
progress: state.getProgress(),
|
|
49302
|
+
});
|
|
49303
|
+
}
|
|
49304
|
+
/**
|
|
49305
|
+
* Clears previously rendered lines and writes a new frame only where needed.
|
|
49306
|
+
*/
|
|
49307
|
+
function render(options) {
|
|
49308
|
+
if (isRendering || isDisposed) {
|
|
48935
49309
|
return;
|
|
48936
49310
|
}
|
|
48937
49311
|
isRendering = true;
|
|
48938
49312
|
try {
|
|
48939
|
-
const lines =
|
|
48940
|
-
|
|
48941
|
-
|
|
48942
|
-
process.stdout.write(`\x1b[${previousFrameLineCount}A`);
|
|
48943
|
-
}
|
|
48944
|
-
for (let i = 0; i < lines.length; i++) {
|
|
48945
|
-
clearLine(process.stdout, 0);
|
|
48946
|
-
cursorTo(process.stdout, 0);
|
|
48947
|
-
process.stdout.write(lines[i]);
|
|
48948
|
-
if (i < lines.length - 1) {
|
|
48949
|
-
process.stdout.write('\n');
|
|
48950
|
-
}
|
|
49313
|
+
const lines = buildFrameLines();
|
|
49314
|
+
if (previousFrameLines.length === 0 || previousFrameLines.length !== lines.length) {
|
|
49315
|
+
renderFullFrame(lines);
|
|
48951
49316
|
}
|
|
48952
|
-
|
|
48953
|
-
|
|
48954
|
-
for (let i = lines.length; i < previousFrameLineCount; i++) {
|
|
48955
|
-
process.stdout.write('\n');
|
|
48956
|
-
clearLine(process.stdout, 0);
|
|
48957
|
-
cursorTo(process.stdout, 0);
|
|
48958
|
-
}
|
|
48959
|
-
// Move back up to the end of the current frame.
|
|
48960
|
-
const overshoot = previousFrameLineCount - lines.length;
|
|
48961
|
-
if (overshoot > 0) {
|
|
48962
|
-
process.stdout.write(`\x1b[${overshoot}A`);
|
|
48963
|
-
}
|
|
49317
|
+
else {
|
|
49318
|
+
renderChangedLines(lines);
|
|
48964
49319
|
}
|
|
48965
|
-
|
|
49320
|
+
previousFrameLines = [...lines];
|
|
48966
49321
|
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
49322
|
+
if (!(options === null || options === void 0 ? void 0 : options.skipAutoRefresh)) {
|
|
49323
|
+
scheduleAutoRefresh();
|
|
49324
|
+
}
|
|
48967
49325
|
}
|
|
48968
49326
|
finally {
|
|
48969
49327
|
isRendering = false;
|
|
48970
49328
|
}
|
|
48971
49329
|
}
|
|
48972
|
-
|
|
48973
|
-
|
|
48974
|
-
|
|
48975
|
-
|
|
48976
|
-
const w = getTerminalWidth();
|
|
48977
|
-
const sep = colors.gray('\u2500'.repeat(w - 2));
|
|
48978
|
-
const spinner = SPINNER_FRAMES[spinnerFrame];
|
|
48979
|
-
const { config, phase, currentPromptLabel, currentAttempt, maxAttempts, statusMessage, agentOutputLines, errors, } = state;
|
|
48980
|
-
const progress = state.getProgress();
|
|
48981
|
-
const isPaused = getPauseState() !== 'RUNNING';
|
|
48982
|
-
const isActive = phase === 'running' || phase === 'verifying' || phase === 'loading';
|
|
48983
|
-
const lines = [];
|
|
48984
|
-
// --- Branding ---
|
|
48985
|
-
lines.push(colors.bold.cyan('\u2728 Promptbook Coder'));
|
|
48986
|
-
// --- Config ---
|
|
48987
|
-
let configLine1 = `Agent: ${colors.bold.green(config.agentName)}`;
|
|
48988
|
-
if (config.modelName) {
|
|
48989
|
-
configLine1 += ` \u2502 Model: ${colors.bold(config.modelName)}`;
|
|
48990
|
-
}
|
|
48991
|
-
if (config.thinkingLevel) {
|
|
48992
|
-
configLine1 += ` \u2502 Thinking: ${colors.bold(config.thinkingLevel)}`;
|
|
48993
|
-
}
|
|
48994
|
-
lines.push(configLine1);
|
|
48995
|
-
let configLine2 = '';
|
|
48996
|
-
if (config.context) {
|
|
48997
|
-
configLine2 += `Context: ${colors.yellow(config.context)} \u2502 `;
|
|
48998
|
-
}
|
|
48999
|
-
configLine2 += `Priority: \u2265${config.priority}`;
|
|
49000
|
-
if (config.testCommand) {
|
|
49001
|
-
configLine2 += ` \u2502 Test: ${colors.gray(config.testCommand)}`;
|
|
49002
|
-
}
|
|
49003
|
-
lines.push(configLine2);
|
|
49004
|
-
// --- Separator ---
|
|
49005
|
-
lines.push(sep);
|
|
49006
|
-
// --- Progress ---
|
|
49007
|
-
const progressSummary = [
|
|
49008
|
-
`${progress.sessionDone}/${progress.sessionTotal} Prompts (${progress.totalPrompts} total)`,
|
|
49009
|
-
`${progress.elapsedText}/${progress.estimatedTotalText}`,
|
|
49010
|
-
`Est. done ${progress.estimatedLabel}`,
|
|
49011
|
-
].join(' \u2502 ');
|
|
49012
|
-
lines.push(progressSummary);
|
|
49013
|
-
lines.push(buildProgressBar(progress.percentage));
|
|
49014
|
-
// --- Separator ---
|
|
49015
|
-
lines.push(sep);
|
|
49016
|
-
// --- Current prompt ---
|
|
49017
|
-
if (currentPromptLabel) {
|
|
49018
|
-
const spinnerPrefix = isActive ? colors.yellow(`${spinner} `) : ' ';
|
|
49019
|
-
lines.push(spinnerPrefix + colors.bold(currentPromptLabel));
|
|
49020
|
-
lines.push(colors.gray(`Attempt ${currentAttempt}/${maxAttempts} \u2502 ${statusMessage}`));
|
|
49330
|
+
const keypressHandler = (_str, key) => {
|
|
49331
|
+
if (key.ctrl && key.name === 'c') {
|
|
49332
|
+
cleanup();
|
|
49333
|
+
process.exit(0);
|
|
49021
49334
|
}
|
|
49022
|
-
|
|
49023
|
-
|
|
49024
|
-
|
|
49025
|
-
|
|
49026
|
-
|
|
49027
|
-
|
|
49028
|
-
|
|
49029
|
-
|
|
49030
|
-
|
|
49031
|
-
|
|
49032
|
-
|
|
49033
|
-
|
|
49034
|
-
|
|
49035
|
-
|
|
49036
|
-
|
|
49037
|
-
|
|
49038
|
-
|
|
49039
|
-
|
|
49040
|
-
|
|
49041
|
-
lines.push(colors.red(`\u2717 ${err}`));
|
|
49042
|
-
}
|
|
49043
|
-
}
|
|
49044
|
-
// --- Separator ---
|
|
49045
|
-
lines.push(sep);
|
|
49046
|
-
// --- Controls ---
|
|
49047
|
-
const pauseLabel = isPaused
|
|
49048
|
-
? colors.bgYellow.black(' PAUSED ') + colors.gray(' [P] Resume \u2502 Ctrl+C Exit')
|
|
49049
|
-
: colors.gray('[P] Pause \u2502 Ctrl+C Exit');
|
|
49050
|
-
lines.push(pauseLabel);
|
|
49051
|
-
return lines;
|
|
49052
|
-
}
|
|
49053
|
-
// Initial render.
|
|
49335
|
+
if (key.name === 'p') {
|
|
49336
|
+
if (getPauseState() === 'RUNNING') {
|
|
49337
|
+
requestPause();
|
|
49338
|
+
}
|
|
49339
|
+
else {
|
|
49340
|
+
requestResume();
|
|
49341
|
+
}
|
|
49342
|
+
scheduleRender();
|
|
49343
|
+
return;
|
|
49344
|
+
}
|
|
49345
|
+
if ((key.name === 'return' || key.name === 'enter') && pendingEnterResolver) {
|
|
49346
|
+
const resolvePendingEnter = pendingEnterResolver;
|
|
49347
|
+
pendingEnterResolver = undefined;
|
|
49348
|
+
state.setPendingEnterLabel(undefined);
|
|
49349
|
+
resolvePendingEnter();
|
|
49350
|
+
}
|
|
49351
|
+
};
|
|
49352
|
+
process.stdin.on('keypress', keypressHandler);
|
|
49353
|
+
process.stdout.on('resize', scheduleRender);
|
|
49054
49354
|
process.stdout.write('\n');
|
|
49055
49355
|
render();
|
|
49056
|
-
const interval = setInterval(scheduleRender, UI_REFRESH_INTERVAL_MS);
|
|
49057
|
-
// Listen for state changes and schedule a re-render (debounced).
|
|
49058
49356
|
state.on('change', scheduleRender);
|
|
49059
|
-
|
|
49357
|
+
/**
|
|
49358
|
+
* Tears down the terminal UI and restores console / stdin state.
|
|
49359
|
+
*/
|
|
49060
49360
|
function cleanup() {
|
|
49061
|
-
|
|
49361
|
+
if (isDisposed) {
|
|
49362
|
+
return;
|
|
49363
|
+
}
|
|
49364
|
+
if (autoRefreshTimeout) {
|
|
49365
|
+
clearTimeout(autoRefreshTimeout);
|
|
49366
|
+
autoRefreshTimeout = undefined;
|
|
49367
|
+
}
|
|
49062
49368
|
state.off('change', scheduleRender);
|
|
49063
49369
|
process.stdin.off('keypress', keypressHandler);
|
|
49370
|
+
process.stdout.off('resize', scheduleRender);
|
|
49064
49371
|
if (process.stdin.isTTY) {
|
|
49065
49372
|
process.stdin.setRawMode(false);
|
|
49066
49373
|
}
|
|
49374
|
+
const resolvePendingEnter = pendingEnterResolver;
|
|
49375
|
+
pendingEnterResolver = undefined;
|
|
49376
|
+
resolvePendingEnter === null || resolvePendingEnter === void 0 ? void 0 : resolvePendingEnter();
|
|
49067
49377
|
isCapturing = false;
|
|
49068
49378
|
console.info = originalConsoleInfo;
|
|
49069
49379
|
console.warn = originalConsoleWarn;
|
|
49070
49380
|
console.error = originalConsoleError;
|
|
49071
49381
|
console.log = originalConsoleLog;
|
|
49072
|
-
|
|
49073
|
-
render();
|
|
49382
|
+
render({ skipAutoRefresh: true });
|
|
49074
49383
|
process.stdout.write('\n');
|
|
49384
|
+
isDisposed = true;
|
|
49075
49385
|
}
|
|
49076
49386
|
return {
|
|
49077
49387
|
state,
|
|
@@ -49081,6 +49391,19 @@ function renderCoderRunUi(startTime) {
|
|
|
49081
49391
|
stopCapturingAgentOutput() {
|
|
49082
49392
|
isCapturing = false;
|
|
49083
49393
|
},
|
|
49394
|
+
waitForEnter(actionLabel) {
|
|
49395
|
+
if (pendingEnterResolver) {
|
|
49396
|
+
throw new Error('Coder run UI is already waiting for Enter.');
|
|
49397
|
+
}
|
|
49398
|
+
state.setPendingEnterLabel(actionLabel);
|
|
49399
|
+
scheduleRender();
|
|
49400
|
+
return new Promise((resolve) => {
|
|
49401
|
+
pendingEnterResolver = () => {
|
|
49402
|
+
scheduleRender();
|
|
49403
|
+
resolve();
|
|
49404
|
+
};
|
|
49405
|
+
});
|
|
49406
|
+
},
|
|
49084
49407
|
cleanup,
|
|
49085
49408
|
};
|
|
49086
49409
|
}
|
|
@@ -49148,11 +49471,11 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49148
49471
|
`));
|
|
49149
49472
|
}
|
|
49150
49473
|
const runStartDate = moment();
|
|
49151
|
-
const
|
|
49152
|
-
const progressDisplay = options.dryRun ||
|
|
49153
|
-
const uiHandle =
|
|
49474
|
+
const isRichUiEnabled = !options.dryRun && !options.noUi && Boolean(process.stdout.isTTY);
|
|
49475
|
+
const progressDisplay = options.dryRun || options.noUi || isRichUiEnabled ? undefined : new CliProgressDisplay(runStartDate, options.priority);
|
|
49476
|
+
const uiHandle = isRichUiEnabled ? renderCoderRunUi(runStartDate) : undefined;
|
|
49154
49477
|
// When the Ink UI is active it handles keyboard input itself, so skip the raw stdin listener.
|
|
49155
|
-
if (!
|
|
49478
|
+
if (!isRichUiEnabled) {
|
|
49156
49479
|
listenForPause();
|
|
49157
49480
|
}
|
|
49158
49481
|
try {
|
|
@@ -49268,17 +49591,19 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49268
49591
|
let hasWaitedForStart = false;
|
|
49269
49592
|
while (just(true)) {
|
|
49270
49593
|
await checkPause({
|
|
49271
|
-
silent:
|
|
49594
|
+
silent: isRichUiEnabled,
|
|
49272
49595
|
onPaused: () => {
|
|
49596
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49273
49597
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49274
49598
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('paused');
|
|
49275
49599
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Paused');
|
|
49276
49600
|
},
|
|
49277
49601
|
onResumed: () => {
|
|
49602
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49278
49603
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49279
49604
|
},
|
|
49280
49605
|
});
|
|
49281
|
-
if (
|
|
49606
|
+
if (isRichUiEnabled) {
|
|
49282
49607
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
49283
49608
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Loading prompts...');
|
|
49284
49609
|
}
|
|
@@ -49286,17 +49611,17 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49286
49611
|
const stats = summarizePrompts(promptFiles, options.priority);
|
|
49287
49612
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|
|
49288
49613
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(stats);
|
|
49289
|
-
if (!
|
|
49614
|
+
if (!isRichUiEnabled) {
|
|
49290
49615
|
printStats(stats, options.priority);
|
|
49291
49616
|
}
|
|
49292
49617
|
const nextPrompt = findNextTodoPrompt(promptFiles, options.priority);
|
|
49293
49618
|
if (!hasShownUpcomingTasks) {
|
|
49294
|
-
if (stats.toBeWritten > 0 && !
|
|
49619
|
+
if (stats.toBeWritten > 0 && !isRichUiEnabled) {
|
|
49295
49620
|
console.info(colors.yellow('Following prompts need to be written:'));
|
|
49296
49621
|
printPromptsToBeWritten(promptFiles, options.priority);
|
|
49297
49622
|
console.info('');
|
|
49298
49623
|
}
|
|
49299
|
-
if (!
|
|
49624
|
+
if (!isRichUiEnabled) {
|
|
49300
49625
|
printUpcomingTasks(listUpcomingTasks(promptFiles, options.priority));
|
|
49301
49626
|
}
|
|
49302
49627
|
hasShownUpcomingTasks = true;
|
|
@@ -49306,7 +49631,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49306
49631
|
const message = 'No prompts ready for agent.';
|
|
49307
49632
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
49308
49633
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
49309
|
-
if (!
|
|
49634
|
+
if (!isRichUiEnabled) {
|
|
49310
49635
|
console.info(colors.yellow(message));
|
|
49311
49636
|
}
|
|
49312
49637
|
}
|
|
@@ -49314,16 +49639,28 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49314
49639
|
const message = 'All prompts are done.';
|
|
49315
49640
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
49316
49641
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
49317
|
-
if (!
|
|
49642
|
+
if (!isRichUiEnabled) {
|
|
49318
49643
|
console.info(colors.green(message));
|
|
49319
49644
|
}
|
|
49320
49645
|
}
|
|
49321
49646
|
return;
|
|
49322
49647
|
}
|
|
49648
|
+
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
49323
49649
|
if (options.waitForUser) {
|
|
49650
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49324
49651
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49325
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.
|
|
49326
|
-
|
|
49652
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
49653
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
49654
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(hasWaitedForStart ? 'Waiting for confirmation to continue' : 'Waiting for confirmation to start');
|
|
49655
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([buildPromptSummary(nextPrompt.file, nextPrompt.section)]);
|
|
49656
|
+
if (isRichUiEnabled) {
|
|
49657
|
+
await (uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.waitForEnter(hasWaitedForStart ? 'Continue' : 'Start'));
|
|
49658
|
+
}
|
|
49659
|
+
else {
|
|
49660
|
+
await waitForPromptStart(nextPrompt.file, nextPrompt.section, !hasWaitedForStart);
|
|
49661
|
+
}
|
|
49662
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([]);
|
|
49663
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49327
49664
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49328
49665
|
hasWaitedForStart = true;
|
|
49329
49666
|
}
|
|
@@ -49333,9 +49670,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49333
49670
|
const commitMessage = buildCommitMessage(nextPrompt.file, nextPrompt.section);
|
|
49334
49671
|
const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
|
|
49335
49672
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
49336
|
-
|
|
49337
|
-
const promptRoundArtifacts = createCoderRunPromptRoundArtifacts(options.preserveLogs);
|
|
49338
|
-
if (isUiMode) {
|
|
49673
|
+
if (isRichUiEnabled) {
|
|
49339
49674
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
49340
49675
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
49341
49676
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
@@ -49345,69 +49680,78 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49345
49680
|
}
|
|
49346
49681
|
const promptExecutionStartedDate = moment();
|
|
49347
49682
|
let attemptCount = 1;
|
|
49348
|
-
let promptRoundOutcome = 'failure';
|
|
49349
49683
|
const roundChangedFilesSnapshot = options.normalizeLineEndings
|
|
49350
49684
|
? await captureChangedFilesSnapshot(process.cwd())
|
|
49351
49685
|
: undefined;
|
|
49352
|
-
|
|
49353
|
-
|
|
49354
|
-
|
|
49355
|
-
|
|
49356
|
-
|
|
49357
|
-
|
|
49358
|
-
|
|
49359
|
-
|
|
49360
|
-
|
|
49361
|
-
|
|
49362
|
-
|
|
49363
|
-
|
|
49364
|
-
|
|
49365
|
-
|
|
49366
|
-
|
|
49367
|
-
|
|
49368
|
-
|
|
49369
|
-
|
|
49370
|
-
|
|
49371
|
-
|
|
49372
|
-
|
|
49373
|
-
|
|
49374
|
-
|
|
49375
|
-
|
|
49376
|
-
|
|
49377
|
-
|
|
49378
|
-
|
|
49379
|
-
|
|
49380
|
-
|
|
49381
|
-
|
|
49686
|
+
await withPromptRuntimeLog(scriptPath, async (logPath) => {
|
|
49687
|
+
try {
|
|
49688
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
49689
|
+
const result = await runPromptWithTestFeedback({
|
|
49690
|
+
runner,
|
|
49691
|
+
prompt: codexPrompt,
|
|
49692
|
+
scriptPath,
|
|
49693
|
+
projectPath: process.cwd(),
|
|
49694
|
+
promptLabel,
|
|
49695
|
+
testCommand: options.testCommand,
|
|
49696
|
+
preserveArtifactsOnSuccess: options.preserveLogs,
|
|
49697
|
+
logPath,
|
|
49698
|
+
onAttemptStarted: (nextAttemptCount) => {
|
|
49699
|
+
attemptCount = nextAttemptCount;
|
|
49700
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
|
|
49701
|
+
if (nextAttemptCount > 1) {
|
|
49702
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
|
|
49703
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
|
|
49704
|
+
}
|
|
49705
|
+
},
|
|
49706
|
+
});
|
|
49707
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49708
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
|
|
49709
|
+
markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
|
|
49710
|
+
await writePromptFile(nextPrompt.file);
|
|
49711
|
+
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49712
|
+
if (options.waitForUser) {
|
|
49713
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49714
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49715
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
49716
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Review the commit preview and confirm to continue');
|
|
49717
|
+
if (isRichUiEnabled) {
|
|
49718
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines(formatCommitMessageForDisplay(commitMessage)
|
|
49719
|
+
.split(/\r?\n/)
|
|
49720
|
+
.map((line) => line.trim()));
|
|
49721
|
+
await (uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.waitForEnter('Commit'));
|
|
49722
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([]);
|
|
49723
|
+
}
|
|
49724
|
+
else {
|
|
49382
49725
|
printCommitMessage(commitMessage);
|
|
49383
49726
|
await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
|
|
49384
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49385
49727
|
}
|
|
49386
|
-
|
|
49387
|
-
|
|
49388
|
-
promptRoundOutcome = 'success';
|
|
49389
|
-
}
|
|
49390
|
-
catch (error) {
|
|
49391
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49392
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
49393
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
49394
|
-
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
49395
|
-
await writePromptFile(nextPrompt.file);
|
|
49396
|
-
await writePromptErrorLog({
|
|
49397
|
-
file: nextPrompt.file,
|
|
49398
|
-
section: nextPrompt.section,
|
|
49399
|
-
runnerName: runnerMetadata.runnerName,
|
|
49400
|
-
modelName: runnerMetadata.modelName,
|
|
49401
|
-
error,
|
|
49402
|
-
});
|
|
49403
|
-
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49404
|
-
throw error;
|
|
49728
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49729
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49405
49730
|
}
|
|
49406
|
-
|
|
49407
|
-
|
|
49408
|
-
|
|
49409
|
-
|
|
49410
|
-
|
|
49731
|
+
await commitChanges(commitMessage, {
|
|
49732
|
+
autoPush: options.autoPush,
|
|
49733
|
+
// Keep the live runtime log out of default commits because it is deleted after a successful round.
|
|
49734
|
+
excludePaths: options.preserveLogs ? undefined : [logPath],
|
|
49735
|
+
});
|
|
49736
|
+
await runPostPromptAutoMigrationIfEnabled(options);
|
|
49737
|
+
}
|
|
49738
|
+
catch (error) {
|
|
49739
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49740
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
49741
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
49742
|
+
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
49743
|
+
await writePromptFile(nextPrompt.file);
|
|
49744
|
+
await writePromptErrorLog({
|
|
49745
|
+
file: nextPrompt.file,
|
|
49746
|
+
section: nextPrompt.section,
|
|
49747
|
+
runnerName: runnerMetadata.runnerName,
|
|
49748
|
+
modelName: runnerMetadata.modelName,
|
|
49749
|
+
error,
|
|
49750
|
+
});
|
|
49751
|
+
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49752
|
+
throw error;
|
|
49753
|
+
}
|
|
49754
|
+
}, { preserveArtifactsOnSuccess: options.preserveLogs });
|
|
49411
49755
|
}
|
|
49412
49756
|
}
|
|
49413
49757
|
finally {
|