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