@promptbook/cli 0.112.0-44 → 0.112.0-45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.es.js +675 -491
- 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/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/renderCoderRunUi.d.ts +2 -0
- package/esm/src/avatars/Avatar.d.ts +7 -0
- package/esm/src/avatars/avatarRenderingUtils.d.ts +117 -0
- package/esm/src/avatars/index.d.ts +6 -0
- package/esm/src/avatars/renderAvatarVisual.d.ts +9 -0
- package/esm/src/avatars/types/AvatarDefinition.d.ts +20 -0
- package/esm/src/avatars/types/AvatarVisualDefinition.d.ts +96 -0
- package/esm/src/avatars/visuals/avatarVisualRegistry.d.ts +16 -0
- package/esm/src/avatars/visuals/minecraftAvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/octopusAvatarVisual.d.ts +7 -0
- package/esm/src/avatars/visuals/pixelArtAvatarVisual.d.ts +7 -0
- package/esm/src/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 +675 -491
- 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/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/renderCoderRunUi.d.ts +2 -0
- package/umd/src/avatars/Avatar.d.ts +7 -0
- package/umd/src/avatars/avatarRenderingUtils.d.ts +117 -0
- package/umd/src/avatars/index.d.ts +6 -0
- package/umd/src/avatars/renderAvatarVisual.d.ts +9 -0
- package/umd/src/avatars/types/AvatarDefinition.d.ts +20 -0
- package/umd/src/avatars/types/AvatarVisualDefinition.d.ts +96 -0
- package/umd/src/avatars/visuals/avatarVisualRegistry.d.ts +16 -0
- package/umd/src/avatars/visuals/minecraftAvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/octopusAvatarVisual.d.ts +7 -0
- package/umd/src/avatars/visuals/pixelArtAvatarVisual.d.ts +7 -0
- package/umd/src/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-45';
|
|
62
62
|
/**
|
|
63
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
64
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -3005,6 +3005,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
3005
3005
|
Features:
|
|
3006
3006
|
- Automatically stages and commits changes with agent identity
|
|
3007
3007
|
- Optional post-commit git push with explicit --auto-push opt-in
|
|
3008
|
+
- Optional --preserve-logs keeps temp prompt/log artifacts after successful rounds
|
|
3009
|
+
- Optional --no-ui keeps plain streaming console output for logging and debugging
|
|
3008
3010
|
- Supports GPG signing of commits
|
|
3009
3011
|
- Optional post-prompt verification with test-feedback retries
|
|
3010
3012
|
- Progress tracking and interactive controls
|
|
@@ -3020,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.
|
|
44826
44981
|
*/
|
|
44827
|
-
|
|
44982
|
+
function shouldDeleteTemporaryArtifact({ preserveArtifactsOnSuccess, hasFailed, }) {
|
|
44983
|
+
return !preserveArtifactsOnSuccess && !hasFailed;
|
|
44984
|
+
}
|
|
44985
|
+
|
|
44986
|
+
/**
|
|
44987
|
+
* Runs one prompt-processing round with a dedicated temporary runtime log file that is cleaned up only after successful non-preserved runs.
|
|
44988
|
+
*/
|
|
44989
|
+
async function withPromptRuntimeLog(scriptPath, handler, options) {
|
|
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
|
*/
|
|
@@ -46737,6 +46846,15 @@ function buildPromptLabelForDisplay(file, section) {
|
|
|
46737
46846
|
return `${relative(process.cwd(), file.path).replace(/\\/g, '/')}#${section.startLine + 1}`;
|
|
46738
46847
|
}
|
|
46739
46848
|
|
|
46849
|
+
/**
|
|
46850
|
+
* Extracts a short summary line from a prompt section.
|
|
46851
|
+
*/
|
|
46852
|
+
function buildPromptSummary(file, section) {
|
|
46853
|
+
const lines = buildCodexPrompt(file, section).split(/\r?\n/);
|
|
46854
|
+
const firstLine = lines.find((line) => line.trim() !== '');
|
|
46855
|
+
return (firstLine === null || firstLine === void 0 ? void 0 : firstLine.trim()) || '(empty prompt)';
|
|
46856
|
+
}
|
|
46857
|
+
|
|
46740
46858
|
/**
|
|
46741
46859
|
* Builds the script path for a prompt section.
|
|
46742
46860
|
*/
|
|
@@ -46796,15 +46914,6 @@ function findNextTodoPrompt(files, minimumPriority = 0) {
|
|
|
46796
46914
|
return nextPrompt;
|
|
46797
46915
|
}
|
|
46798
46916
|
|
|
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
46917
|
/**
|
|
46809
46918
|
* Lists upcoming tasks that are ready to run (no authoring placeholders).
|
|
46810
46919
|
*/
|
|
@@ -47356,25 +47465,29 @@ async function runBashScriptWithOutput(options) {
|
|
|
47356
47465
|
}
|
|
47357
47466
|
|
|
47358
47467
|
/**
|
|
47359
|
-
* Creates a temporary script file, runs a handler, and
|
|
47468
|
+
* Creates a temporary script file, runs a handler, and cleans it up unless preservation is requested or the run fails.
|
|
47360
47469
|
*/
|
|
47361
47470
|
async function withTempScript(options, handler) {
|
|
47362
|
-
const { scriptPath, scriptContent
|
|
47471
|
+
const { scriptPath, scriptContent } = options;
|
|
47472
|
+
let hasFailed = false;
|
|
47363
47473
|
await mkdir(dirname$1(scriptPath), { recursive: true });
|
|
47364
47474
|
await writeFile(scriptPath, scriptContent, 'utf-8');
|
|
47365
|
-
promptRoundArtifacts === null || promptRoundArtifacts === void 0 ? void 0 : promptRoundArtifacts.track(scriptPath, getPromptRoundArtifactKindFromScriptPath(scriptPath));
|
|
47366
47475
|
try {
|
|
47367
47476
|
return await handler(scriptPath);
|
|
47368
47477
|
}
|
|
47478
|
+
catch (error) {
|
|
47479
|
+
hasFailed = true;
|
|
47480
|
+
throw error;
|
|
47481
|
+
}
|
|
47369
47482
|
finally {
|
|
47370
|
-
if (
|
|
47483
|
+
if (shouldDeleteTemporaryArtifact({ preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess, hasFailed })) {
|
|
47371
47484
|
await unlink(scriptPath).catch(() => undefined);
|
|
47372
47485
|
}
|
|
47373
47486
|
}
|
|
47374
47487
|
}
|
|
47375
47488
|
|
|
47376
47489
|
/**
|
|
47377
|
-
* Creates a temporary script file, runs it, captures output, and cleans it up
|
|
47490
|
+
* Creates a temporary script file, runs it, captures output, and cleans it up unless preservation is requested or the run fails.
|
|
47378
47491
|
*/
|
|
47379
47492
|
async function $runGoScriptWithOutput(options) {
|
|
47380
47493
|
return await withTempScript(options, async (scriptPath) => {
|
|
@@ -47477,7 +47590,7 @@ class ClaudeCodeRunner {
|
|
|
47477
47590
|
scriptPath: options.scriptPath,
|
|
47478
47591
|
scriptContent,
|
|
47479
47592
|
logPath: options.logPath,
|
|
47480
|
-
|
|
47593
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47481
47594
|
});
|
|
47482
47595
|
const usage = parseClaudeCodeJsonOutput(output);
|
|
47483
47596
|
return { usage };
|
|
@@ -47485,7 +47598,7 @@ class ClaudeCodeRunner {
|
|
|
47485
47598
|
}
|
|
47486
47599
|
|
|
47487
47600
|
/**
|
|
47488
|
-
* Creates a temporary script file, runs it, and cleans it up
|
|
47601
|
+
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
47489
47602
|
*/
|
|
47490
47603
|
async function $runGoScript(options) {
|
|
47491
47604
|
await withTempScript(options, async (scriptPath) => {
|
|
@@ -47541,7 +47654,7 @@ class ClineRunner {
|
|
|
47541
47654
|
scriptPath: options.scriptPath,
|
|
47542
47655
|
scriptContent,
|
|
47543
47656
|
logPath: options.logPath,
|
|
47544
|
-
|
|
47657
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47545
47658
|
});
|
|
47546
47659
|
return { usage: UNCERTAIN_USAGE };
|
|
47547
47660
|
}
|
|
@@ -47666,7 +47779,7 @@ class GeminiRunner {
|
|
|
47666
47779
|
scriptPath: options.scriptPath,
|
|
47667
47780
|
scriptContent,
|
|
47668
47781
|
logPath: options.logPath,
|
|
47669
|
-
|
|
47782
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47670
47783
|
});
|
|
47671
47784
|
const usage = parseGeminiUsageFromOutput(output, options.prompt, this.options.model);
|
|
47672
47785
|
return { usage };
|
|
@@ -47723,7 +47836,7 @@ class GitHubCopilotRunner {
|
|
|
47723
47836
|
scriptPath: options.scriptPath,
|
|
47724
47837
|
scriptContent,
|
|
47725
47838
|
logPath: options.logPath,
|
|
47726
|
-
|
|
47839
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
47727
47840
|
});
|
|
47728
47841
|
return { usage: UNCERTAIN_USAGE };
|
|
47729
47842
|
}
|
|
@@ -47899,7 +48012,7 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
47899
48012
|
}
|
|
47900
48013
|
|
|
47901
48014
|
/**
|
|
47902
|
-
* Creates a temporary script file, runs it, waits for a completion marker and idle time, and
|
|
48015
|
+
* Creates a temporary script file, runs it, waits for a completion marker and idle time, and cleans it up unless preservation is requested or the run fails.
|
|
47903
48016
|
* Returns the captured output for post-processing.
|
|
47904
48017
|
*/
|
|
47905
48018
|
async function $runGoScriptUntilMarkerIdle(options) {
|
|
@@ -48288,7 +48401,7 @@ class OpenAiCodexRunner {
|
|
|
48288
48401
|
completionLineMatcher: CODEX_COMPLETION_LINE,
|
|
48289
48402
|
idleTimeoutMs: CODEX_COMPLETION_IDLE_MS,
|
|
48290
48403
|
logPath: options.logPath,
|
|
48291
|
-
|
|
48404
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48292
48405
|
});
|
|
48293
48406
|
this.rateLimitBackoff.reset();
|
|
48294
48407
|
return { usage: buildCodexUsageFromOutput(output, this.options.model) };
|
|
@@ -48423,7 +48536,7 @@ class OpencodeRunner {
|
|
|
48423
48536
|
scriptPath: options.scriptPath,
|
|
48424
48537
|
scriptContent,
|
|
48425
48538
|
logPath: options.logPath,
|
|
48426
|
-
|
|
48539
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48427
48540
|
});
|
|
48428
48541
|
}
|
|
48429
48542
|
catch (error) {
|
|
@@ -48451,6 +48564,7 @@ async function runPromptTestCommand(options) {
|
|
|
48451
48564
|
${options.command}
|
|
48452
48565
|
`),
|
|
48453
48566
|
logPath: options.logPath,
|
|
48567
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48454
48568
|
});
|
|
48455
48569
|
}
|
|
48456
48570
|
|
|
@@ -48475,7 +48589,7 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48475
48589
|
scriptPath: options.scriptPath,
|
|
48476
48590
|
projectPath: options.projectPath,
|
|
48477
48591
|
logPath: options.logPath,
|
|
48478
|
-
|
|
48592
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48479
48593
|
});
|
|
48480
48594
|
return { ...result, attemptCount: 1 };
|
|
48481
48595
|
}
|
|
@@ -48488,7 +48602,7 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48488
48602
|
scriptPath: options.scriptPath,
|
|
48489
48603
|
projectPath: options.projectPath,
|
|
48490
48604
|
logPath: options.logPath,
|
|
48491
|
-
|
|
48605
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48492
48606
|
});
|
|
48493
48607
|
console.info(colors.gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
|
|
48494
48608
|
try {
|
|
@@ -48497,6 +48611,7 @@ async function runPromptWithTestFeedback(options) {
|
|
|
48497
48611
|
projectPath: options.projectPath,
|
|
48498
48612
|
scriptPath: buildPromptTestScriptPath(options.scriptPath),
|
|
48499
48613
|
logPath: options.logPath,
|
|
48614
|
+
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
48500
48615
|
});
|
|
48501
48616
|
return { ...result, attemptCount };
|
|
48502
48617
|
}
|
|
@@ -48578,24 +48693,203 @@ function buildPromptTestScriptPath(scriptPath) {
|
|
|
48578
48693
|
}
|
|
48579
48694
|
|
|
48580
48695
|
/**
|
|
48581
|
-
* Maximum number of
|
|
48582
|
-
*
|
|
48583
|
-
* @private internal constant of coder run UI
|
|
48696
|
+
* Maximum number of output lines reserved for agent output in the UI.
|
|
48584
48697
|
*/
|
|
48585
|
-
const
|
|
48698
|
+
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48586
48699
|
/**
|
|
48587
|
-
*
|
|
48700
|
+
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
48701
|
+
*/
|
|
48702
|
+
function buildCoderRunUiFrame(options) {
|
|
48703
|
+
const totalWidth = Math.max(56, Math.min(options.terminalWidth, 96));
|
|
48704
|
+
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
48705
|
+
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
48706
|
+
const sessionScopeLine = options.progress.sessionTotal > 0
|
|
48707
|
+
? `Working on ${options.progress.currentPromptIndex}/${options.progress.sessionTotal} prompts with Priority ≥${options.config.priority}`
|
|
48708
|
+
: `No runnable prompts with Priority ≥${options.config.priority}`;
|
|
48709
|
+
const sessionCountLine = `Done ${options.progress.sessionDone}/${options.progress.sessionTotal} this run · Repo total ${options.progress.totalPrompts}`;
|
|
48710
|
+
const sessionQueueParts = [];
|
|
48711
|
+
if (options.progress.skippedPrompts > 0) {
|
|
48712
|
+
sessionQueueParts.push(`Skipping ${formatPromptCount(options.progress.skippedPrompts)} with Priority <${options.config.priority}`);
|
|
48713
|
+
}
|
|
48714
|
+
if (options.progress.toBeWrittenPrompts > 0) {
|
|
48715
|
+
sessionQueueParts.push(`Write first ${formatPromptCount(options.progress.toBeWrittenPrompts)}`);
|
|
48716
|
+
}
|
|
48717
|
+
const sessionLines = [
|
|
48718
|
+
`${buildPhaseBadge(options.phase, options.pauseState)} ${fitPlainText(options.statusMessage, totalWidth - 18)}`,
|
|
48719
|
+
sessionScopeLine,
|
|
48720
|
+
sessionCountLine,
|
|
48721
|
+
...(sessionQueueParts.length > 0 ? [sessionQueueParts.join(' · ')] : []),
|
|
48722
|
+
`Elapsed ${options.progress.elapsedText} · Est. total ${options.progress.estimatedTotalText} · Est. done ${options.progress.estimatedLabel}`,
|
|
48723
|
+
buildProgressBar(options.progress.percentage, totalWidth - 6, `${options.progress.percentage}% complete (${options.progress.sessionDone}/${options.progress.sessionTotal} done)`),
|
|
48724
|
+
];
|
|
48725
|
+
const metadataParts = [options.config.agentName || 'No agent selected'];
|
|
48726
|
+
if (options.config.modelName) {
|
|
48727
|
+
metadataParts.push(options.config.modelName);
|
|
48728
|
+
}
|
|
48729
|
+
if (options.config.thinkingLevel) {
|
|
48730
|
+
metadataParts.push(`thinking ${options.config.thinkingLevel}`);
|
|
48731
|
+
}
|
|
48732
|
+
const runnerDetails = [
|
|
48733
|
+
[`${colors.bgCyan.black(' PTBK ')}`, colors.bgBlue.white(' CODER '), colors.bold.white(' Promptbook Coder')]
|
|
48734
|
+
.join(''),
|
|
48735
|
+
metadataParts.join(' · '),
|
|
48736
|
+
buildConfigSummaryLine(options.config),
|
|
48737
|
+
];
|
|
48738
|
+
const currentTaskLines = options.currentPromptLabel
|
|
48739
|
+
? [
|
|
48740
|
+
`${promptStatusPrefix}${colors.bold.white(fitPlainText(options.currentPromptLabel, totalWidth - 8))}`,
|
|
48741
|
+
`Attempt ${options.currentAttempt}/${options.maxAttempts} · ${options.statusMessage}`,
|
|
48742
|
+
...options.detailLines.map((detailLine) => `• ${detailLine}`),
|
|
48743
|
+
]
|
|
48744
|
+
: [options.statusMessage, ...options.detailLines.map((detailLine) => `• ${detailLine}`)];
|
|
48745
|
+
const visibleOutputLines = options.agentOutputLines.length > 0
|
|
48746
|
+
? options.agentOutputLines.slice(-MAX_VISIBLE_OUTPUT_LINES).map((line) => `› ${stripAnsi(line)}`)
|
|
48747
|
+
: ['No live agent output yet.'];
|
|
48748
|
+
const controls = buildControlPills(options.pauseState, options.pendingEnterLabel).join(' ');
|
|
48749
|
+
const frame = [
|
|
48750
|
+
...renderBox('Brand', runnerDetails, totalWidth, colors.cyan.bold),
|
|
48751
|
+
...renderBox('Session', sessionLines, totalWidth, colors.yellow.bold),
|
|
48752
|
+
...renderBox(options.currentPromptLabel ? 'Current task' : 'Queue', currentTaskLines, totalWidth, colors.magenta.bold),
|
|
48753
|
+
...renderBox('Live output', visibleOutputLines, totalWidth, colors.green.bold),
|
|
48754
|
+
];
|
|
48755
|
+
if (options.errors.length > 0) {
|
|
48756
|
+
frame.push(...renderBox('Errors', options.errors.map((errorLine) => `${colors.red('✗')} ${errorLine}`), totalWidth, colors.red.bold));
|
|
48757
|
+
}
|
|
48758
|
+
frame.push(...renderBox('Controls', [controls], totalWidth, colors.white.bold));
|
|
48759
|
+
return frame;
|
|
48760
|
+
}
|
|
48761
|
+
/**
|
|
48762
|
+
* Renders a framed box with a colored title and padded body lines.
|
|
48763
|
+
*/
|
|
48764
|
+
function renderBox(title, lines, totalWidth, colorizeTitle) {
|
|
48765
|
+
const bodyWidth = Math.max(10, totalWidth - 4);
|
|
48766
|
+
const titleText = ` ${title} `;
|
|
48767
|
+
const topBorder = colors.gray('┌') +
|
|
48768
|
+
colorizeTitle(titleText) +
|
|
48769
|
+
colors.gray('─'.repeat(Math.max(0, totalWidth - 2 - titleText.length)) + '┐');
|
|
48770
|
+
const body = lines.map((line) => {
|
|
48771
|
+
const paddedLine = padAnsiText(line, bodyWidth);
|
|
48772
|
+
return colors.gray('│ ') + paddedLine + colors.gray(' │');
|
|
48773
|
+
});
|
|
48774
|
+
const bottomBorder = colors.gray(`└${'─'.repeat(totalWidth - 2)}┘`);
|
|
48775
|
+
return [topBorder, ...body, bottomBorder];
|
|
48776
|
+
}
|
|
48777
|
+
/**
|
|
48778
|
+
* Builds the compact config summary line shown in the branding box.
|
|
48779
|
+
*/
|
|
48780
|
+
function buildConfigSummaryLine(config) {
|
|
48781
|
+
const parts = [`Priority ≥${config.priority}`];
|
|
48782
|
+
if (config.context) {
|
|
48783
|
+
parts.unshift(`Context ${config.context}`);
|
|
48784
|
+
}
|
|
48785
|
+
if (config.testCommand) {
|
|
48786
|
+
parts.push(`Test ${config.testCommand}`);
|
|
48787
|
+
}
|
|
48788
|
+
return parts.join(' · ');
|
|
48789
|
+
}
|
|
48790
|
+
/**
|
|
48791
|
+
* Builds the colored phase badge shown in the session box.
|
|
48792
|
+
*/
|
|
48793
|
+
function buildPhaseBadge(phase, pauseState) {
|
|
48794
|
+
if (pauseState !== 'RUNNING' || phase === 'paused') {
|
|
48795
|
+
return colors.bgYellow.black(' PAUSED ');
|
|
48796
|
+
}
|
|
48797
|
+
switch (phase) {
|
|
48798
|
+
case 'loading':
|
|
48799
|
+
case 'initializing':
|
|
48800
|
+
return colors.bgCyan.black(' LOADING ');
|
|
48801
|
+
case 'running':
|
|
48802
|
+
return colors.bgGreen.black(' RUNNING ');
|
|
48803
|
+
case 'verifying':
|
|
48804
|
+
return colors.bgMagenta.white(' VERIFYING ');
|
|
48805
|
+
case 'waiting':
|
|
48806
|
+
return colors.bgBlue.white(' WAITING ');
|
|
48807
|
+
case 'done':
|
|
48808
|
+
return colors.bgGreen.black(' DONE ');
|
|
48809
|
+
case 'error':
|
|
48810
|
+
return colors.bgRed.white(' ERROR ');
|
|
48811
|
+
default:
|
|
48812
|
+
return colors.bgWhite.black(' READY ');
|
|
48813
|
+
}
|
|
48814
|
+
}
|
|
48815
|
+
/**
|
|
48816
|
+
* Builds the progress bar shown in the session box.
|
|
48817
|
+
*/
|
|
48818
|
+
function buildProgressBar(percentage, availableWidth, label) {
|
|
48819
|
+
const percentageLabel = label;
|
|
48820
|
+
const barWidth = Math.max(10, availableWidth - percentageLabel.length - 1);
|
|
48821
|
+
const filledWidth = Math.round((percentage / 100) * barWidth);
|
|
48822
|
+
const emptyWidth = Math.max(0, barWidth - filledWidth);
|
|
48823
|
+
return `${colors.green('█'.repeat(filledWidth))}${colors.gray('░'.repeat(emptyWidth))} ${percentageLabel}`;
|
|
48824
|
+
}
|
|
48825
|
+
/**
|
|
48826
|
+
* Formats a prompt count with singular/plural wording.
|
|
48827
|
+
*/
|
|
48828
|
+
function formatPromptCount(count) {
|
|
48829
|
+
return `${count} prompt${count === 1 ? '' : 's'}`;
|
|
48830
|
+
}
|
|
48831
|
+
/**
|
|
48832
|
+
* Builds the control pills shown in the footer box.
|
|
48833
|
+
*/
|
|
48834
|
+
function buildControlPills(pauseState, pendingEnterLabel) {
|
|
48835
|
+
const pills = [];
|
|
48836
|
+
if (pendingEnterLabel) {
|
|
48837
|
+
pills.push(colors.bgWhite.black(' ENTER ') + colors.white(` ${pendingEnterLabel}`));
|
|
48838
|
+
}
|
|
48839
|
+
pills.push(pauseState === 'RUNNING'
|
|
48840
|
+
? colors.bgYellow.black(' P ') + colors.white(' Pause')
|
|
48841
|
+
: colors.bgYellow.black(' P ') + colors.white(' Resume'));
|
|
48842
|
+
pills.push(colors.bgRed.white(' CTRL+C ') + colors.white(' Exit'));
|
|
48843
|
+
return pills;
|
|
48844
|
+
}
|
|
48845
|
+
/**
|
|
48846
|
+
* Pads or truncates a possibly ANSI-colored line to the target visible width.
|
|
48847
|
+
*/
|
|
48848
|
+
function padAnsiText(text, width) {
|
|
48849
|
+
const fittedText = fitAnsiText(text, width);
|
|
48850
|
+
return fittedText + ' '.repeat(Math.max(0, width - visibleLength(fittedText)));
|
|
48851
|
+
}
|
|
48852
|
+
/**
|
|
48853
|
+
* Truncates a possibly ANSI-colored line to the target visible width.
|
|
48854
|
+
*/
|
|
48855
|
+
function fitAnsiText(text, width) {
|
|
48856
|
+
if (visibleLength(text) <= width) {
|
|
48857
|
+
return text;
|
|
48858
|
+
}
|
|
48859
|
+
return fitPlainText(stripAnsi(text), width);
|
|
48860
|
+
}
|
|
48861
|
+
/**
|
|
48862
|
+
* Truncates a plain-text line to the target width with an ellipsis.
|
|
48863
|
+
*/
|
|
48864
|
+
function fitPlainText(text, width) {
|
|
48865
|
+
if (text.length <= width) {
|
|
48866
|
+
return text;
|
|
48867
|
+
}
|
|
48868
|
+
if (width <= 3) {
|
|
48869
|
+
return '.'.repeat(width);
|
|
48870
|
+
}
|
|
48871
|
+
return `${text.slice(0, width - 3)}...`;
|
|
48872
|
+
}
|
|
48873
|
+
/**
|
|
48874
|
+
* Measures visible string width by stripping ANSI escape codes.
|
|
48875
|
+
*/
|
|
48876
|
+
function visibleLength(text) {
|
|
48877
|
+
return stripAnsi(text).length;
|
|
48878
|
+
}
|
|
48879
|
+
/**
|
|
48880
|
+
* Strips ANSI escape codes from a string.
|
|
48881
|
+
*/
|
|
48882
|
+
function stripAnsi(text) {
|
|
48883
|
+
// eslint-disable-next-line no-control-regex
|
|
48884
|
+
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48885
|
+
}
|
|
48886
|
+
|
|
48887
|
+
/**
|
|
48888
|
+
* Maximum number of agent output lines kept in the scrolling output area.
|
|
48588
48889
|
*
|
|
48589
48890
|
* @private internal constant of coder run UI
|
|
48590
48891
|
*/
|
|
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
|
-
};
|
|
48892
|
+
const MAX_AGENT_OUTPUT_LINES = 12;
|
|
48599
48893
|
/**
|
|
48600
48894
|
* Reactive state manager for the coder run terminal UI.
|
|
48601
48895
|
*
|
|
@@ -48611,35 +48905,27 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48611
48905
|
this.currentPromptLabel = '';
|
|
48612
48906
|
this.currentAttempt = 1;
|
|
48613
48907
|
this.maxAttempts = 3;
|
|
48908
|
+
this.detailLines = [];
|
|
48614
48909
|
this.agentOutputLines = [];
|
|
48615
48910
|
this.phase = 'initializing';
|
|
48616
48911
|
this.statusMessage = 'Initializing...';
|
|
48617
48912
|
this.errors = [];
|
|
48618
48913
|
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();
|
|
48914
|
+
this.timer = new CoderRunTimer(startTime, true);
|
|
48626
48915
|
}
|
|
48627
48916
|
/**
|
|
48628
48917
|
* Pauses the elapsed timer (e.g. while waiting for user input or paused state).
|
|
48629
48918
|
*/
|
|
48630
48919
|
pauseTimer() {
|
|
48631
|
-
|
|
48632
|
-
|
|
48633
|
-
}
|
|
48920
|
+
this.timer.pause();
|
|
48921
|
+
this.emitChange();
|
|
48634
48922
|
}
|
|
48635
48923
|
/**
|
|
48636
48924
|
* Resumes the elapsed timer after a pause.
|
|
48637
48925
|
*/
|
|
48638
48926
|
resumeTimer() {
|
|
48639
|
-
|
|
48640
|
-
|
|
48641
|
-
this.pausedSince = undefined;
|
|
48642
|
-
}
|
|
48927
|
+
this.timer.resume();
|
|
48928
|
+
this.emitChange();
|
|
48643
48929
|
}
|
|
48644
48930
|
/**
|
|
48645
48931
|
* Replaces the configuration shown in the UI header.
|
|
@@ -48663,41 +48949,15 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48663
48949
|
*/
|
|
48664
48950
|
getProgress() {
|
|
48665
48951
|
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
|
-
};
|
|
48952
|
+
return buildCoderRunProgressSnapshot(this.stats, this.timer.getElapsedDuration(), (_a = this.initialDone) !== null && _a !== void 0 ? _a : this.stats.done);
|
|
48695
48953
|
}
|
|
48696
48954
|
/**
|
|
48697
48955
|
* Sets the label of the prompt currently being processed and resets per-prompt state.
|
|
48698
48956
|
*/
|
|
48699
48957
|
setCurrentPrompt(label) {
|
|
48700
48958
|
this.currentPromptLabel = label;
|
|
48959
|
+
this.detailLines = [];
|
|
48960
|
+
this.pendingEnterLabel = undefined;
|
|
48701
48961
|
this.agentOutputLines = [];
|
|
48702
48962
|
this.currentAttempt = 1;
|
|
48703
48963
|
this.emitChange();
|
|
@@ -48737,6 +48997,20 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48737
48997
|
this.statusMessage = message;
|
|
48738
48998
|
this.emitChange();
|
|
48739
48999
|
}
|
|
49000
|
+
/**
|
|
49001
|
+
* Replaces the contextual detail lines shown beneath the current prompt status.
|
|
49002
|
+
*/
|
|
49003
|
+
setDetailLines(detailLines) {
|
|
49004
|
+
this.detailLines = detailLines.filter((detailLine) => detailLine.trim() !== '');
|
|
49005
|
+
this.emitChange();
|
|
49006
|
+
}
|
|
49007
|
+
/**
|
|
49008
|
+
* Sets or clears the Enter-key action label shown in the controls panel.
|
|
49009
|
+
*/
|
|
49010
|
+
setPendingEnterLabel(pendingEnterLabel) {
|
|
49011
|
+
this.pendingEnterLabel = pendingEnterLabel;
|
|
49012
|
+
this.emitChange();
|
|
49013
|
+
}
|
|
48740
49014
|
/**
|
|
48741
49015
|
* Appends an error message to the error list shown in the UI.
|
|
48742
49016
|
*/
|
|
@@ -48748,31 +49022,6 @@ class CoderRunUiState extends EventEmitter {
|
|
|
48748
49022
|
this.emit('change');
|
|
48749
49023
|
}
|
|
48750
49024
|
}
|
|
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
49025
|
|
|
48777
49026
|
/**
|
|
48778
49027
|
* Refresh interval for the terminal UI in milliseconds.
|
|
@@ -48780,18 +49029,6 @@ function formatDurationBrief(duration) {
|
|
|
48780
49029
|
* @private internal constant of coder run UI
|
|
48781
49030
|
*/
|
|
48782
49031
|
const UI_REFRESH_INTERVAL_MS = 200;
|
|
48783
|
-
/**
|
|
48784
|
-
* Character width used for the text progress bar.
|
|
48785
|
-
*
|
|
48786
|
-
* @private internal constant of coder run UI
|
|
48787
|
-
*/
|
|
48788
|
-
const PROGRESS_BAR_WIDTH = 40;
|
|
48789
|
-
/**
|
|
48790
|
-
* Maximum number of output lines reserved for agent output in the UI.
|
|
48791
|
-
*
|
|
48792
|
-
* @private internal constant of coder run UI
|
|
48793
|
-
*/
|
|
48794
|
-
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48795
49032
|
/**
|
|
48796
49033
|
* Spinner animation frames.
|
|
48797
49034
|
*
|
|
@@ -48810,31 +49047,12 @@ const SPINNER_FRAMES = [
|
|
|
48810
49047
|
'\u280F',
|
|
48811
49048
|
];
|
|
48812
49049
|
/**
|
|
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.
|
|
49050
|
+
* Returns the usable terminal width, capped at 96.
|
|
48823
49051
|
*
|
|
48824
49052
|
* @private internal utility of coder run UI
|
|
48825
49053
|
*/
|
|
48826
49054
|
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}%`;
|
|
49055
|
+
return Math.min(process.stdout.columns || 80, 96);
|
|
48838
49056
|
}
|
|
48839
49057
|
/**
|
|
48840
49058
|
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
@@ -48855,21 +49073,20 @@ function renderCoderRunUi(startTime) {
|
|
|
48855
49073
|
state,
|
|
48856
49074
|
startCapturingAgentOutput: () => { },
|
|
48857
49075
|
stopCapturingAgentOutput: () => { },
|
|
49076
|
+
waitForEnter: async () => { },
|
|
48858
49077
|
cleanup: () => { },
|
|
48859
49078
|
};
|
|
48860
49079
|
}
|
|
48861
|
-
// --- Console interception ---
|
|
48862
49080
|
const originalConsoleInfo = console.info;
|
|
48863
49081
|
const originalConsoleWarn = console.warn;
|
|
48864
49082
|
const originalConsoleError = console.error;
|
|
48865
49083
|
const originalConsoleLog = console.log;
|
|
48866
49084
|
let isCapturing = false;
|
|
49085
|
+
let pendingEnterResolver;
|
|
48867
49086
|
console.info = (...args) => {
|
|
48868
49087
|
if (isCapturing) {
|
|
48869
49088
|
state.addAgentOutput(args.map(String).join(' '));
|
|
48870
49089
|
}
|
|
48871
|
-
// In UI mode, non-captured output is intentionally suppressed
|
|
48872
|
-
// so it does not interfere with the repainted frame.
|
|
48873
49090
|
};
|
|
48874
49091
|
console.warn = (...args) => {
|
|
48875
49092
|
if (isCapturing) {
|
|
@@ -48886,29 +49103,11 @@ function renderCoderRunUi(startTime) {
|
|
|
48886
49103
|
state.addAgentOutput(args.map(String).join(' '));
|
|
48887
49104
|
}
|
|
48888
49105
|
};
|
|
48889
|
-
// --- Keyboard input (pause) ---
|
|
48890
49106
|
const readline = require('readline');
|
|
48891
49107
|
readline.emitKeypressEvents(process.stdin);
|
|
48892
49108
|
if (process.stdin.isTTY) {
|
|
48893
49109
|
process.stdin.setRawMode(true);
|
|
48894
49110
|
}
|
|
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
49111
|
let spinnerFrame = 0;
|
|
48913
49112
|
let previousFrameLineCount = 0;
|
|
48914
49113
|
let isRendering = false;
|
|
@@ -48936,8 +49135,22 @@ function renderCoderRunUi(startTime) {
|
|
|
48936
49135
|
}
|
|
48937
49136
|
isRendering = true;
|
|
48938
49137
|
try {
|
|
48939
|
-
const lines =
|
|
48940
|
-
|
|
49138
|
+
const lines = buildCoderRunUiFrame({
|
|
49139
|
+
terminalWidth: getTerminalWidth(),
|
|
49140
|
+
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
49141
|
+
pauseState: getPauseState(),
|
|
49142
|
+
config: state.config,
|
|
49143
|
+
phase: state.phase,
|
|
49144
|
+
currentPromptLabel: state.currentPromptLabel,
|
|
49145
|
+
currentAttempt: state.currentAttempt,
|
|
49146
|
+
maxAttempts: state.maxAttempts,
|
|
49147
|
+
statusMessage: state.statusMessage,
|
|
49148
|
+
detailLines: state.detailLines,
|
|
49149
|
+
pendingEnterLabel: state.pendingEnterLabel,
|
|
49150
|
+
agentOutputLines: state.agentOutputLines,
|
|
49151
|
+
errors: state.errors,
|
|
49152
|
+
progress: state.getProgress(),
|
|
49153
|
+
});
|
|
48941
49154
|
if (previousFrameLineCount > 0) {
|
|
48942
49155
|
process.stdout.write(`\x1b[${previousFrameLineCount}A`);
|
|
48943
49156
|
}
|
|
@@ -48949,14 +49162,12 @@ function renderCoderRunUi(startTime) {
|
|
|
48949
49162
|
process.stdout.write('\n');
|
|
48950
49163
|
}
|
|
48951
49164
|
}
|
|
48952
|
-
// Clear any leftover lines from a previous longer frame.
|
|
48953
49165
|
if (lines.length < previousFrameLineCount) {
|
|
48954
49166
|
for (let i = lines.length; i < previousFrameLineCount; i++) {
|
|
48955
49167
|
process.stdout.write('\n');
|
|
48956
49168
|
clearLine(process.stdout, 0);
|
|
48957
49169
|
cursorTo(process.stdout, 0);
|
|
48958
49170
|
}
|
|
48959
|
-
// Move back up to the end of the current frame.
|
|
48960
49171
|
const overshoot = previousFrameLineCount - lines.length;
|
|
48961
49172
|
if (overshoot > 0) {
|
|
48962
49173
|
process.stdout.write(`\x1b[${overshoot}A`);
|
|
@@ -48969,94 +49180,35 @@ function renderCoderRunUi(startTime) {
|
|
|
48969
49180
|
isRendering = false;
|
|
48970
49181
|
}
|
|
48971
49182
|
}
|
|
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}`));
|
|
49183
|
+
const keypressHandler = (_str, key) => {
|
|
49184
|
+
if (key.ctrl && key.name === 'c') {
|
|
49185
|
+
cleanup();
|
|
49186
|
+
process.exit(0);
|
|
49021
49187
|
}
|
|
49022
|
-
|
|
49023
|
-
|
|
49024
|
-
|
|
49025
|
-
|
|
49026
|
-
|
|
49027
|
-
|
|
49028
|
-
|
|
49029
|
-
|
|
49030
|
-
|
|
49031
|
-
|
|
49032
|
-
|
|
49033
|
-
|
|
49034
|
-
|
|
49035
|
-
|
|
49036
|
-
}
|
|
49037
|
-
|
|
49038
|
-
|
|
49039
|
-
lines.push('');
|
|
49040
|
-
for (const err of errors) {
|
|
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.
|
|
49188
|
+
if (key.name === 'p') {
|
|
49189
|
+
if (getPauseState() === 'RUNNING') {
|
|
49190
|
+
requestPause();
|
|
49191
|
+
}
|
|
49192
|
+
else {
|
|
49193
|
+
requestResume();
|
|
49194
|
+
}
|
|
49195
|
+
return;
|
|
49196
|
+
}
|
|
49197
|
+
if ((key.name === 'return' || key.name === 'enter') && pendingEnterResolver) {
|
|
49198
|
+
const resolvePendingEnter = pendingEnterResolver;
|
|
49199
|
+
pendingEnterResolver = undefined;
|
|
49200
|
+
state.setPendingEnterLabel(undefined);
|
|
49201
|
+
resolvePendingEnter();
|
|
49202
|
+
}
|
|
49203
|
+
};
|
|
49204
|
+
process.stdin.on('keypress', keypressHandler);
|
|
49054
49205
|
process.stdout.write('\n');
|
|
49055
49206
|
render();
|
|
49056
49207
|
const interval = setInterval(scheduleRender, UI_REFRESH_INTERVAL_MS);
|
|
49057
|
-
// Listen for state changes and schedule a re-render (debounced).
|
|
49058
49208
|
state.on('change', scheduleRender);
|
|
49059
|
-
|
|
49209
|
+
/**
|
|
49210
|
+
* Tears down the terminal UI and restores console / stdin state.
|
|
49211
|
+
*/
|
|
49060
49212
|
function cleanup() {
|
|
49061
49213
|
clearInterval(interval);
|
|
49062
49214
|
state.off('change', scheduleRender);
|
|
@@ -49064,12 +49216,14 @@ function renderCoderRunUi(startTime) {
|
|
|
49064
49216
|
if (process.stdin.isTTY) {
|
|
49065
49217
|
process.stdin.setRawMode(false);
|
|
49066
49218
|
}
|
|
49219
|
+
const resolvePendingEnter = pendingEnterResolver;
|
|
49220
|
+
pendingEnterResolver = undefined;
|
|
49221
|
+
resolvePendingEnter === null || resolvePendingEnter === void 0 ? void 0 : resolvePendingEnter();
|
|
49067
49222
|
isCapturing = false;
|
|
49068
49223
|
console.info = originalConsoleInfo;
|
|
49069
49224
|
console.warn = originalConsoleWarn;
|
|
49070
49225
|
console.error = originalConsoleError;
|
|
49071
49226
|
console.log = originalConsoleLog;
|
|
49072
|
-
// Render one final frame so the user sees the last state.
|
|
49073
49227
|
render();
|
|
49074
49228
|
process.stdout.write('\n');
|
|
49075
49229
|
}
|
|
@@ -49081,6 +49235,19 @@ function renderCoderRunUi(startTime) {
|
|
|
49081
49235
|
stopCapturingAgentOutput() {
|
|
49082
49236
|
isCapturing = false;
|
|
49083
49237
|
},
|
|
49238
|
+
waitForEnter(actionLabel) {
|
|
49239
|
+
if (pendingEnterResolver) {
|
|
49240
|
+
throw new Error('Coder run UI is already waiting for Enter.');
|
|
49241
|
+
}
|
|
49242
|
+
state.setPendingEnterLabel(actionLabel);
|
|
49243
|
+
scheduleRender();
|
|
49244
|
+
return new Promise((resolve) => {
|
|
49245
|
+
pendingEnterResolver = () => {
|
|
49246
|
+
scheduleRender();
|
|
49247
|
+
resolve();
|
|
49248
|
+
};
|
|
49249
|
+
});
|
|
49250
|
+
},
|
|
49084
49251
|
cleanup,
|
|
49085
49252
|
};
|
|
49086
49253
|
}
|
|
@@ -49148,11 +49315,11 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49148
49315
|
`));
|
|
49149
49316
|
}
|
|
49150
49317
|
const runStartDate = moment();
|
|
49151
|
-
const
|
|
49152
|
-
const progressDisplay = options.dryRun ||
|
|
49153
|
-
const uiHandle =
|
|
49318
|
+
const isRichUiEnabled = !options.dryRun && !options.noUi && Boolean(process.stdout.isTTY);
|
|
49319
|
+
const progressDisplay = options.dryRun || options.noUi || isRichUiEnabled ? undefined : new CliProgressDisplay(runStartDate, options.priority);
|
|
49320
|
+
const uiHandle = isRichUiEnabled ? renderCoderRunUi(runStartDate) : undefined;
|
|
49154
49321
|
// When the Ink UI is active it handles keyboard input itself, so skip the raw stdin listener.
|
|
49155
|
-
if (!
|
|
49322
|
+
if (!isRichUiEnabled) {
|
|
49156
49323
|
listenForPause();
|
|
49157
49324
|
}
|
|
49158
49325
|
try {
|
|
@@ -49268,17 +49435,19 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49268
49435
|
let hasWaitedForStart = false;
|
|
49269
49436
|
while (just(true)) {
|
|
49270
49437
|
await checkPause({
|
|
49271
|
-
silent:
|
|
49438
|
+
silent: isRichUiEnabled,
|
|
49272
49439
|
onPaused: () => {
|
|
49440
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49273
49441
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49274
49442
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('paused');
|
|
49275
49443
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Paused');
|
|
49276
49444
|
},
|
|
49277
49445
|
onResumed: () => {
|
|
49446
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49278
49447
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49279
49448
|
},
|
|
49280
49449
|
});
|
|
49281
|
-
if (
|
|
49450
|
+
if (isRichUiEnabled) {
|
|
49282
49451
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
49283
49452
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Loading prompts...');
|
|
49284
49453
|
}
|
|
@@ -49286,17 +49455,17 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49286
49455
|
const stats = summarizePrompts(promptFiles, options.priority);
|
|
49287
49456
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|
|
49288
49457
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(stats);
|
|
49289
|
-
if (!
|
|
49458
|
+
if (!isRichUiEnabled) {
|
|
49290
49459
|
printStats(stats, options.priority);
|
|
49291
49460
|
}
|
|
49292
49461
|
const nextPrompt = findNextTodoPrompt(promptFiles, options.priority);
|
|
49293
49462
|
if (!hasShownUpcomingTasks) {
|
|
49294
|
-
if (stats.toBeWritten > 0 && !
|
|
49463
|
+
if (stats.toBeWritten > 0 && !isRichUiEnabled) {
|
|
49295
49464
|
console.info(colors.yellow('Following prompts need to be written:'));
|
|
49296
49465
|
printPromptsToBeWritten(promptFiles, options.priority);
|
|
49297
49466
|
console.info('');
|
|
49298
49467
|
}
|
|
49299
|
-
if (!
|
|
49468
|
+
if (!isRichUiEnabled) {
|
|
49300
49469
|
printUpcomingTasks(listUpcomingTasks(promptFiles, options.priority));
|
|
49301
49470
|
}
|
|
49302
49471
|
hasShownUpcomingTasks = true;
|
|
@@ -49306,7 +49475,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49306
49475
|
const message = 'No prompts ready for agent.';
|
|
49307
49476
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
49308
49477
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
49309
|
-
if (!
|
|
49478
|
+
if (!isRichUiEnabled) {
|
|
49310
49479
|
console.info(colors.yellow(message));
|
|
49311
49480
|
}
|
|
49312
49481
|
}
|
|
@@ -49314,16 +49483,28 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49314
49483
|
const message = 'All prompts are done.';
|
|
49315
49484
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
49316
49485
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
49317
|
-
if (!
|
|
49486
|
+
if (!isRichUiEnabled) {
|
|
49318
49487
|
console.info(colors.green(message));
|
|
49319
49488
|
}
|
|
49320
49489
|
}
|
|
49321
49490
|
return;
|
|
49322
49491
|
}
|
|
49492
|
+
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
49323
49493
|
if (options.waitForUser) {
|
|
49494
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49324
49495
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49325
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.
|
|
49326
|
-
|
|
49496
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
49497
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
49498
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(hasWaitedForStart ? 'Waiting for confirmation to continue' : 'Waiting for confirmation to start');
|
|
49499
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([buildPromptSummary(nextPrompt.file, nextPrompt.section)]);
|
|
49500
|
+
if (isRichUiEnabled) {
|
|
49501
|
+
await (uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.waitForEnter(hasWaitedForStart ? 'Continue' : 'Start'));
|
|
49502
|
+
}
|
|
49503
|
+
else {
|
|
49504
|
+
await waitForPromptStart(nextPrompt.file, nextPrompt.section, !hasWaitedForStart);
|
|
49505
|
+
}
|
|
49506
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([]);
|
|
49507
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49327
49508
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49328
49509
|
hasWaitedForStart = true;
|
|
49329
49510
|
}
|
|
@@ -49333,9 +49514,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49333
49514
|
const commitMessage = buildCommitMessage(nextPrompt.file, nextPrompt.section);
|
|
49334
49515
|
const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
|
|
49335
49516
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
49336
|
-
|
|
49337
|
-
const promptRoundArtifacts = createCoderRunPromptRoundArtifacts(options.preserveLogs);
|
|
49338
|
-
if (isUiMode) {
|
|
49517
|
+
if (isRichUiEnabled) {
|
|
49339
49518
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
49340
49519
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
49341
49520
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
@@ -49345,69 +49524,74 @@ async function runCodexPrompts(providedOptions) {
|
|
|
49345
49524
|
}
|
|
49346
49525
|
const promptExecutionStartedDate = moment();
|
|
49347
49526
|
let attemptCount = 1;
|
|
49348
|
-
let promptRoundOutcome = 'failure';
|
|
49349
49527
|
const roundChangedFilesSnapshot = options.normalizeLineEndings
|
|
49350
49528
|
? await captureChangedFilesSnapshot(process.cwd())
|
|
49351
49529
|
: 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
|
-
|
|
49530
|
+
await withPromptRuntimeLog(scriptPath, async (logPath) => {
|
|
49531
|
+
try {
|
|
49532
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
49533
|
+
const result = await runPromptWithTestFeedback({
|
|
49534
|
+
runner,
|
|
49535
|
+
prompt: codexPrompt,
|
|
49536
|
+
scriptPath,
|
|
49537
|
+
projectPath: process.cwd(),
|
|
49538
|
+
promptLabel,
|
|
49539
|
+
testCommand: options.testCommand,
|
|
49540
|
+
preserveArtifactsOnSuccess: options.preserveLogs,
|
|
49541
|
+
logPath,
|
|
49542
|
+
onAttemptStarted: (nextAttemptCount) => {
|
|
49543
|
+
attemptCount = nextAttemptCount;
|
|
49544
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
|
|
49545
|
+
if (nextAttemptCount > 1) {
|
|
49546
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
|
|
49547
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
|
|
49548
|
+
}
|
|
49549
|
+
},
|
|
49550
|
+
});
|
|
49551
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49552
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
|
|
49553
|
+
markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
|
|
49554
|
+
await writePromptFile(nextPrompt.file);
|
|
49555
|
+
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49556
|
+
if (options.waitForUser) {
|
|
49557
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.pauseTimer();
|
|
49558
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49559
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('waiting');
|
|
49560
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Review the commit preview and confirm to continue');
|
|
49561
|
+
if (isRichUiEnabled) {
|
|
49562
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines(formatCommitMessageForDisplay(commitMessage)
|
|
49563
|
+
.split(/\r?\n/)
|
|
49564
|
+
.map((line) => line.trim()));
|
|
49565
|
+
await (uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.waitForEnter('Commit'));
|
|
49566
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setDetailLines([]);
|
|
49567
|
+
}
|
|
49568
|
+
else {
|
|
49382
49569
|
printCommitMessage(commitMessage);
|
|
49383
49570
|
await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
|
|
49384
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49385
49571
|
}
|
|
49386
|
-
|
|
49387
|
-
|
|
49388
|
-
promptRoundOutcome = 'success';
|
|
49572
|
+
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.resumeTimer();
|
|
49573
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
49389
49574
|
}
|
|
49390
|
-
|
|
49391
|
-
|
|
49392
|
-
|
|
49393
|
-
|
|
49394
|
-
|
|
49395
|
-
|
|
49396
|
-
|
|
49397
|
-
|
|
49398
|
-
|
|
49399
|
-
|
|
49400
|
-
|
|
49401
|
-
|
|
49402
|
-
|
|
49403
|
-
|
|
49404
|
-
|
|
49405
|
-
}
|
|
49406
|
-
|
|
49407
|
-
|
|
49408
|
-
|
|
49409
|
-
|
|
49410
|
-
}
|
|
49575
|
+
await commitChanges(commitMessage, { autoPush: options.autoPush });
|
|
49576
|
+
await runPostPromptAutoMigrationIfEnabled(options);
|
|
49577
|
+
}
|
|
49578
|
+
catch (error) {
|
|
49579
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49580
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
49581
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
49582
|
+
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
49583
|
+
await writePromptFile(nextPrompt.file);
|
|
49584
|
+
await writePromptErrorLog({
|
|
49585
|
+
file: nextPrompt.file,
|
|
49586
|
+
section: nextPrompt.section,
|
|
49587
|
+
runnerName: runnerMetadata.runnerName,
|
|
49588
|
+
modelName: runnerMetadata.modelName,
|
|
49589
|
+
error,
|
|
49590
|
+
});
|
|
49591
|
+
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
49592
|
+
throw error;
|
|
49593
|
+
}
|
|
49594
|
+
}, { preserveArtifactsOnSuccess: options.preserveLogs });
|
|
49411
49595
|
}
|
|
49412
49596
|
}
|
|
49413
49597
|
finally {
|