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