@promptbook/cli 0.112.0-43 → 0.112.0-44

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.
Files changed (33) hide show
  1. package/esm/index.es.js +481 -111
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/scripts/run-codex-prompts/common/runGoScript/$runGoScript.d.ts +1 -1
  4. package/esm/scripts/run-codex-prompts/common/runGoScript/$runGoScriptUntilMarkerIdle.d.ts +1 -1
  5. package/esm/scripts/run-codex-prompts/common/runGoScript/$runGoScriptWithOutput.d.ts +1 -1
  6. package/esm/scripts/run-codex-prompts/common/runGoScript/PromptRoundArtifacts.d.ts +35 -0
  7. package/esm/scripts/run-codex-prompts/common/runGoScript/buildScriptLogPath.d.ts +4 -0
  8. package/esm/scripts/run-codex-prompts/common/runGoScript/runBashScriptWithOutput.d.ts +5 -0
  9. package/esm/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +28 -0
  10. package/esm/scripts/run-codex-prompts/common/runGoScript/withPromptRuntimeLog.d.ts +5 -0
  11. package/esm/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
  12. package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -0
  13. package/esm/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -1
  14. package/esm/src/book-2.0/agent-source/TeammateProfileResolver.d.ts +2 -1
  15. package/esm/src/commitments/PERSONA/PERSONA.d.ts +7 -0
  16. package/esm/src/version.d.ts +1 -1
  17. package/package.json +1 -1
  18. package/umd/index.umd.js +480 -110
  19. package/umd/index.umd.js.map +1 -1
  20. package/umd/scripts/run-codex-prompts/common/runGoScript/$runGoScript.d.ts +1 -1
  21. package/umd/scripts/run-codex-prompts/common/runGoScript/$runGoScriptUntilMarkerIdle.d.ts +1 -1
  22. package/umd/scripts/run-codex-prompts/common/runGoScript/$runGoScriptWithOutput.d.ts +1 -1
  23. package/umd/scripts/run-codex-prompts/common/runGoScript/PromptRoundArtifacts.d.ts +35 -0
  24. package/umd/scripts/run-codex-prompts/common/runGoScript/buildScriptLogPath.d.ts +4 -0
  25. package/umd/scripts/run-codex-prompts/common/runGoScript/runBashScriptWithOutput.d.ts +5 -0
  26. package/umd/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +28 -0
  27. package/umd/scripts/run-codex-prompts/common/runGoScript/withPromptRuntimeLog.d.ts +5 -0
  28. package/umd/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
  29. package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -0
  30. package/umd/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -1
  31. package/umd/src/book-2.0/agent-source/TeammateProfileResolver.d.ts +2 -1
  32. package/umd/src/commitments/PERSONA/PERSONA.d.ts +7 -0
  33. package/umd/src/version.d.ts +1 -1
package/esm/index.es.js CHANGED
@@ -4,7 +4,7 @@ import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
4
  import * as fs from 'fs';
5
5
  import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'fs';
6
6
  import { join, basename, dirname, isAbsolute, relative, extname, resolve } from 'path';
7
- import { readFile, writeFile, stat, mkdir, access, constants, readdir, watch, unlink, rm, rename, rmdir } from 'fs/promises';
7
+ import { readFile, writeFile, stat, mkdir, access, constants, readdir, watch, unlink, rm, rename, rmdir, appendFile } from 'fs/promises';
8
8
  import { forTime, forEver } from 'waitasecond';
9
9
  import prompts from 'prompts';
10
10
  import * as dotenv from 'dotenv';
@@ -58,7 +58,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
58
58
  * @generated
59
59
  * @see https://github.com/webgptorg/promptbook
60
60
  */
61
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-43';
61
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-44';
62
62
  /**
63
63
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
64
64
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -3025,12 +3025,13 @@ function $initializeCoderRunCommand(program) {
3025
3025
  command.option('--no-wait', 'Skip user prompts between processing');
3026
3026
  command.option('--ignore-git-changes', 'Skip clean working tree check before running prompts', false);
3027
3027
  command.option('--allow-credits', 'Allow OpenAI Codex runner to spend credits when rate limits are exhausted', false);
3028
+ command.option('--preserve-logs', 'Keep generated runner shells and runtime logs after successful prompt rounds; failures keep them automatically', false);
3028
3029
  command.option('--no-normalize-line-endings', 'Disable automatic LF normalization for files changed in each coding round');
3029
3030
  command.option('--auto-push', 'Automatically git push after each commit', false);
3030
3031
  command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
3031
3032
  command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
3032
3033
  command.action(handleActionErrors(async (cliOptions) => {
3033
- const { dryRun, agent, model, context, test, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
3034
+ const { dryRun, agent, model, context, test, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, preserveLogs, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
3034
3035
  const testCommand = normalizeCommandOptionValue(test);
3035
3036
  // Validate agent
3036
3037
  let agentName = undefined;
@@ -3065,6 +3066,7 @@ function $initializeCoderRunCommand(program) {
3065
3066
  priority,
3066
3067
  normalizeLineEndings,
3067
3068
  allowCredits,
3069
+ preserveLogs,
3068
3070
  autoMigrate,
3069
3071
  allowDestructiveAutoMigrate,
3070
3072
  autoPush,
@@ -18949,7 +18951,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
18949
18951
  * Short one-line description of GOAL.
18950
18952
  */
18951
18953
  get description() {
18952
- return 'Define main **goals** the AI assistant should achieve, with later goals having higher priority.';
18954
+ return 'Define the effective agent **goal**; when multiple goals exist, only the last one stays effective.';
18953
18955
  }
18954
18956
  /**
18955
18957
  * Icon for this commitment.
@@ -18964,12 +18966,14 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
18964
18966
  return spaceTrim$1(`
18965
18967
  # ${this.type}
18966
18968
 
18967
- Defines the main goal which should be achieved by the AI assistant. There can be multiple goals, and later goals are more important than earlier goals.
18969
+ Defines the main goal which should be achieved by the AI assistant.
18970
+ There can be multiple goals in source, but after inheritance/source rewriting only the last \`GOAL\` /\`GOALS\` remains effective.
18968
18971
 
18969
18972
  ## Key aspects
18970
18973
 
18971
18974
  - Both terms work identically and can be used interchangeably.
18972
- - Later goals have higher priority and can override earlier goals.
18975
+ - Later goals overwrite earlier goals.
18976
+ - The public agent profile text is derived from the last goal.
18973
18977
  - Goals provide clear direction and purpose for the agent's responses.
18974
18978
  - Goals influence decision-making and response prioritization.
18975
18979
 
@@ -18982,9 +18986,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
18982
18986
  \`\`\`book
18983
18987
  Customer Support Agent
18984
18988
 
18985
- PERSONA You are a helpful customer support representative
18986
18989
  GOAL Resolve customer issues quickly and efficiently
18987
- GOAL Maintain high customer satisfaction scores
18988
18990
  GOAL Always follow company policies and procedures
18989
18991
  RULE Be polite and professional at all times
18990
18992
  \`\`\`
@@ -18992,9 +18994,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
18992
18994
  \`\`\`book
18993
18995
  Educational Assistant
18994
18996
 
18995
- PERSONA You are an educational assistant specializing in mathematics
18996
18997
  GOAL Help students understand mathematical concepts clearly
18997
- GOAL Encourage critical thinking and problem-solving skills
18998
18998
  GOAL Ensure all explanations are age-appropriate and accessible
18999
18999
  STYLE Use simple language and provide step-by-step explanations
19000
19000
  \`\`\`
@@ -19002,9 +19002,7 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
19002
19002
  \`\`\`book
19003
19003
  Safety-First Assistant
19004
19004
 
19005
- PERSONA You are a general-purpose AI assistant
19006
19005
  GOAL Be helpful and informative in all interactions
19007
- GOAL Provide accurate and reliable information
19008
19006
  GOAL Always prioritize user safety and ethical guidelines
19009
19007
  RULE Never provide harmful or dangerous advice
19010
19008
  \`\`\`
@@ -21863,7 +21861,16 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
21863
21861
  * Short one-line description of PERSONA.
21864
21862
  */
21865
21863
  get description() {
21866
- return 'Define who the agent is: background, expertise, and personality.';
21864
+ return 'Deprecated legacy profile commitment. Prefer `GOAL` for agent profile text and inheritance-safe rewrites.';
21865
+ }
21866
+ /**
21867
+ * Optional UI/docs-only deprecation metadata.
21868
+ */
21869
+ get deprecation() {
21870
+ return {
21871
+ message: 'Use `GOAL` for agent profile text and inheritance-safe rewrites.',
21872
+ replacedBy: ['GOAL'],
21873
+ };
21867
21874
  }
21868
21875
  /**
21869
21876
  * Icon for this commitment.
@@ -21878,16 +21885,24 @@ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
21878
21885
  return spaceTrim$1(`
21879
21886
  # ${this.type}
21880
21887
 
21881
- Defines who the agent is, their background, expertise, and personality traits.
21888
+ Deprecated legacy commitment that defines who the agent is, their background, expertise, and personality traits.
21882
21889
 
21883
- ## Key aspects
21890
+ ## Migration
21884
21891
 
21885
- - Multiple \`PERSONA\` and \`PERSONAE\` commitments are merged together.
21886
- - Both terms work identically and can be used interchangeably.
21887
- - If they are in conflict, the last one takes precedence.
21888
- - You can write persona content in multiple lines.
21892
+ - Existing \`${this.type}\` books still parse and compile.
21893
+ - New books should prefer \`GOAL\`.
21894
+ - Agent profile rendering now prefers the last \`GOAL\` and only falls back to \`${this.type}\` when no goal exists.
21895
+ - Runtime compilation keeps the legacy multi-\`PERSONA\` merge behavior for backward compatibility.
21889
21896
 
21890
- ## Examples
21897
+ ## Preferred replacement
21898
+
21899
+ \`\`\`book
21900
+ Programming Assistant
21901
+
21902
+ GOAL Help the user solve programming problems with practical TypeScript and React guidance.
21903
+ \`\`\`
21904
+
21905
+ ## Legacy compatibility example
21891
21906
 
21892
21907
  \`\`\`book
21893
21908
  Programming Assistant
@@ -22652,7 +22667,7 @@ class TeamCommitmentDefinition extends BaseCommitmentDefinition {
22652
22667
  \`\`\`book
22653
22668
  Legal Assistant
22654
22669
 
22655
- PERSONA An expert software developer
22670
+ GOAL Get expert software-development advice from the teammate when legal discussion needs technical context.
22656
22671
  TEAM You can talk with http://localhost:4440/agents/GMw67JN8TXxN7y to discuss the legal aspects.
22657
22672
  \`\`\`
22658
22673
  `);
@@ -41398,6 +41413,15 @@ const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS',
41398
41413
  * @private internal constant of `createAgentModelRequirementsWithCommitments`
41399
41414
  */
41400
41415
  const DELETE_COMMITMENT_TYPES = new Set(['DELETE', 'CANCEL', 'DISCARD', 'REMOVE']);
41416
+ /**
41417
+ * Commitments whose earlier occurrences are overwritten by the last occurrence in source order.
41418
+ *
41419
+ * @private internal constant of `createAgentModelRequirementsWithCommitments`
41420
+ */
41421
+ const OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE = new Map([
41422
+ ['GOAL', 'GOAL'],
41423
+ ['GOALS', 'GOAL'],
41424
+ ]);
41401
41425
  /**
41402
41426
  * Regex pattern matching markdown horizontal lines that should not be copied into the final system message.
41403
41427
  *
@@ -41448,7 +41472,7 @@ function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
41448
41472
  */
41449
41473
  async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
41450
41474
  const parseResult = parseAgentSourceWithCommitments(agentSource);
41451
- const filteredCommitments = filterDeletedCommitments(parseResult.commitments);
41475
+ const filteredCommitments = filterOverwrittenCommitments(filterDeletedCommitments(parseResult.commitments));
41452
41476
  let requirements = createInitialAgentModelRequirements(parseResult.agentName, modelName);
41453
41477
  requirements = await applyCommitmentsToRequirements(requirements, filteredCommitments, options);
41454
41478
  requirements = aggregateUseCommitmentSystemMessages(requirements, filteredCommitments);
@@ -41459,6 +41483,35 @@ async function createAgentModelRequirementsWithCommitments(agentSource, modelNam
41459
41483
  requirements = await applyPendingInlineKnowledgeSources(requirements, options === null || options === void 0 ? void 0 : options.inlineKnowledgeSourceUploader);
41460
41484
  return finalizeRequirements(requirements);
41461
41485
  }
41486
+ /**
41487
+ * Removes earlier commitments that are overwritten by later commitments of the same semantic group.
41488
+ *
41489
+ * This currently keeps only the last `GOAL` / `GOALS` commitment so inheritance rewrites
41490
+ * and multi-goal sources expose one effective goal to the runtime.
41491
+ *
41492
+ * @param commitments - Parsed commitments after DELETE-like filtering.
41493
+ * @returns Commitments with overwritten entries removed while preserving source order.
41494
+ *
41495
+ * @private internal utility of `createAgentModelRequirementsWithCommitments`
41496
+ */
41497
+ function filterOverwrittenCommitments(commitments) {
41498
+ const seenOverwriteGroups = new Set();
41499
+ const keptCommitments = [];
41500
+ for (let index = commitments.length - 1; index >= 0; index--) {
41501
+ const commitment = commitments[index];
41502
+ const overwriteGroup = OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE.get(commitment.type);
41503
+ if (!overwriteGroup) {
41504
+ keptCommitments.push(commitment);
41505
+ continue;
41506
+ }
41507
+ if (seenOverwriteGroups.has(overwriteGroup)) {
41508
+ continue;
41509
+ }
41510
+ seenOverwriteGroups.add(overwriteGroup);
41511
+ keptCommitments.push(commitment);
41512
+ }
41513
+ return keptCommitments.reverse();
41514
+ }
41462
41515
  /**
41463
41516
  * Creates the initial requirements object with the parsed agent name stored in metadata and an optional model override.
41464
41517
  *
@@ -42101,7 +42154,7 @@ function createDefaultAgentName(agentSource) {
42101
42154
  function parseAgentSource(agentSource) {
42102
42155
  const parseResult = parseAgentSourceWithCommitments(agentSource);
42103
42156
  const resolvedAgentName = parseResult.agentName || createDefaultAgentName(agentSource);
42104
- const personaDescription = extractPersonaDescription(parseResult.commitments);
42157
+ const personaDescription = extractAgentProfileText(parseResult.commitments);
42105
42158
  const initialMessage = extractInitialMessage(parseResult.commitments);
42106
42159
  const parsedProfile = extractParsedAgentProfile(parseResult.commitments);
42107
42160
  ensureMetaFullname(parsedProfile.meta, resolvedAgentName);
@@ -42205,25 +42258,33 @@ const META_COMMITMENT_APPLIERS = {
42205
42258
  */
42206
42259
  const LOCAL_AGENT_REFERENCE_PREFIXES = ['./', '../', '/'];
42207
42260
  /**
42208
- * Builds the combined persona description from PERSONA commitments.
42261
+ * Resolves the public agent profile text from the last GOAL/GOALS commitment,
42262
+ * falling back to the deprecated PERSONA/PERSONAE commitments when no goal exists.
42209
42263
  *
42210
42264
  * @private internal utility of `parseAgentSource`
42211
42265
  */
42212
- function extractPersonaDescription(commitments) {
42213
- let personaDescription = null;
42266
+ function extractAgentProfileText(commitments) {
42267
+ let goalDescription = '';
42268
+ let hasGoalDescription = false;
42269
+ let personaDescription = '';
42270
+ let hasPersonaDescription = false;
42214
42271
  for (const commitment of commitments) {
42215
- if (commitment.type !== 'PERSONA') {
42216
- continue;
42272
+ if (commitment.type === 'GOAL' || commitment.type === 'GOALS') {
42273
+ goalDescription = commitment.content;
42274
+ hasGoalDescription = true;
42217
42275
  }
42218
- if (personaDescription === null) {
42219
- personaDescription = '';
42276
+ if (commitment.type === 'PERSONA' || commitment.type === 'PERSONAE') {
42277
+ personaDescription = commitment.content;
42278
+ hasPersonaDescription = true;
42220
42279
  }
42221
- else {
42222
- personaDescription += `\n\n${personaDescription}`;
42223
- }
42224
- personaDescription += commitment.content;
42225
42280
  }
42226
- return personaDescription;
42281
+ if (hasGoalDescription) {
42282
+ return goalDescription;
42283
+ }
42284
+ if (hasPersonaDescription) {
42285
+ return personaDescription;
42286
+ }
42287
+ return null;
42227
42288
  }
42228
42289
  /**
42229
42290
  * Resolves the last INITIAL MESSAGE commitment, which is the public initial-message value.
@@ -42710,7 +42771,7 @@ async function createAgentModelRequirements(agentSource, modelName, availableMod
42710
42771
  * Selects the best model using the preparePersona function
42711
42772
  * This directly uses preparePersona to ensure DRY principle
42712
42773
  *
42713
- * @param agentSource The agent source to derive persona description from
42774
+ * @param agentSource The agent source to derive effective profile text from
42714
42775
  * @param llmTools LLM tools for preparing persona
42715
42776
  * @returns The name of the best selected model
42716
42777
  *
@@ -42718,9 +42779,9 @@ async function createAgentModelRequirements(agentSource, modelName, availableMod
42718
42779
  */
42719
42780
  async function selectBestModelUsingPersona(agentSource, llmTools) {
42720
42781
  var _a;
42721
- // Parse agent source to get persona description
42782
+ // Parse agent source to get the effective profile description
42722
42783
  const { agentName, personaDescription } = parseAgentSource(agentSource);
42723
- // Use agent name as fallback if no persona description is available
42784
+ // Use agent name as fallback if no profile description is available
42724
42785
  const description = personaDescription || agentName || 'AI Agent';
42725
42786
  try {
42726
42787
  // Use preparePersona directly
@@ -44182,7 +44243,7 @@ var findRefactorCandidates$1 = /*#__PURE__*/Object.freeze({
44182
44243
  /**
44183
44244
  * CLI usage text for this script.
44184
44245
  */
44185
- const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push]';
44246
+ const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--preserve-logs] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push]';
44186
44247
  /**
44187
44248
  * Top-level flags supported by this command.
44188
44249
  */
@@ -44195,6 +44256,7 @@ const KNOWN_OPTION_FLAGS = new Set([
44195
44256
  '--thinking-level',
44196
44257
  '--priority',
44197
44258
  '--allow-credits',
44259
+ '--preserve-logs',
44198
44260
  '--auto-migrate',
44199
44261
  '--allow-destructive-auto-migrate',
44200
44262
  '--no-wait',
@@ -44231,6 +44293,7 @@ function parseRunOptions(args) {
44231
44293
  const ignoreGitChanges = args.includes('--ignore-git-changes');
44232
44294
  const normalizeLineEndings = !args.includes('--no-normalize-line-endings');
44233
44295
  const allowCredits = args.includes('--allow-credits');
44296
+ const preserveLogs = args.includes('--preserve-logs');
44234
44297
  const autoMigrate = args.includes('--auto-migrate');
44235
44298
  const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
44236
44299
  const autoPush = args.includes('--auto-push');
@@ -44256,6 +44319,7 @@ function parseRunOptions(args) {
44256
44319
  ignoreGitChanges,
44257
44320
  normalizeLineEndings,
44258
44321
  allowCredits,
44322
+ preserveLogs,
44259
44323
  autoMigrate,
44260
44324
  allowDestructiveAutoMigrate,
44261
44325
  autoPush,
@@ -44749,6 +44813,91 @@ async function resolveCoderContext(contextReference, currentWorkingDirectory) {
44749
44813
  return readFile(contextPath, 'utf-8');
44750
44814
  }
44751
44815
 
44816
+ /**
44817
+ * Builds the temporary live runtime log path for one prompt script and its sibling test script.
44818
+ */
44819
+ function buildScriptLogPath(scriptPath) {
44820
+ const basePath = scriptPath.replace(/\.test\.sh$/iu, '').replace(/\.sh$/iu, '');
44821
+ return `${basePath}.log.txt`;
44822
+ }
44823
+
44824
+ /**
44825
+ * Runs one prompt-processing round with a dedicated temporary runtime log file and optionally defers cleanup to the round tracker.
44826
+ */
44827
+ async function withPromptRuntimeLog(scriptPath, handler, promptRoundArtifacts) {
44828
+ const logPath = buildScriptLogPath(scriptPath);
44829
+ await unlink(logPath).catch(() => undefined);
44830
+ promptRoundArtifacts === null || promptRoundArtifacts === void 0 ? void 0 : promptRoundArtifacts.track(logPath, 'runtime-log');
44831
+ try {
44832
+ return await handler(logPath);
44833
+ }
44834
+ finally {
44835
+ if (!promptRoundArtifacts) {
44836
+ await unlink(logPath).catch(() => undefined);
44837
+ }
44838
+ }
44839
+ }
44840
+
44841
+ /**
44842
+ * Shared artifact kinds preserved for debugging when a prompt round fails.
44843
+ */
44844
+ const FAILURE_PRESERVED_ARTIFACT_KINDS = new Set(['runner-script', 'runtime-log']);
44845
+ /**
44846
+ * Shared artifact kinds preserved after a successful prompt round when explicitly requested.
44847
+ */
44848
+ const SUCCESS_PRESERVED_ARTIFACT_KINDS = new Set(['runner-script', 'runtime-log']);
44849
+ /**
44850
+ * Empty preserved-artifact set used for successful rounds without `--preserve-logs`.
44851
+ */
44852
+ const NO_PRESERVED_ARTIFACT_KINDS = new Set();
44853
+ /**
44854
+ * Tracks temporary prompt-round artifacts and deletes only those not preserved for the final round outcome.
44855
+ */
44856
+ class PromptRoundArtifacts {
44857
+ /**
44858
+ * Creates a new prompt-round artifact tracker.
44859
+ */
44860
+ constructor(preservedArtifactKindsByOutcome) {
44861
+ this.preservedArtifactKindsByOutcome = preservedArtifactKindsByOutcome;
44862
+ this.trackedArtifacts = new Map();
44863
+ }
44864
+ /**
44865
+ * Registers one temporary artifact for round-final cleanup.
44866
+ */
44867
+ track(path, kind) {
44868
+ this.trackedArtifacts.set(path, kind);
44869
+ }
44870
+ /**
44871
+ * Cleans up all tracked artifacts that should not survive the final round outcome.
44872
+ */
44873
+ async cleanup(outcome) {
44874
+ const preservedArtifactKinds = this.preservedArtifactKindsByOutcome[outcome];
44875
+ const trackedArtifacts = [...this.trackedArtifacts.entries()];
44876
+ this.trackedArtifacts.clear();
44877
+ await Promise.all(trackedArtifacts.map(async ([path, kind]) => {
44878
+ if (preservedArtifactKinds.has(kind)) {
44879
+ return;
44880
+ }
44881
+ await unlink(path).catch(() => undefined);
44882
+ }));
44883
+ }
44884
+ }
44885
+ /**
44886
+ * Creates the default artifact-retention policy used by `ptbk coder run`.
44887
+ */
44888
+ function createCoderRunPromptRoundArtifacts(isPreserveLogs) {
44889
+ return new PromptRoundArtifacts({
44890
+ success: isPreserveLogs ? SUCCESS_PRESERVED_ARTIFACT_KINDS : NO_PRESERVED_ARTIFACT_KINDS,
44891
+ failure: FAILURE_PRESERVED_ARTIFACT_KINDS,
44892
+ });
44893
+ }
44894
+ /**
44895
+ * Derives the tracked artifact kind from one temporary shell path.
44896
+ */
44897
+ function getPromptRoundArtifactKindFromScriptPath(scriptPath) {
44898
+ return scriptPath.toLowerCase().endsWith('.test.sh') ? 'test-script' : 'runner-script';
44899
+ }
44900
+
44752
44901
  /**
44753
44902
  * Waits for the user to press Enter before continuing.
44754
44903
  */
@@ -47052,25 +47201,186 @@ function toPosixPath(filePath) {
47052
47201
  }
47053
47202
 
47054
47203
  /**
47055
- * Creates a temporary script file, runs a handler, and ensures cleanup.
47204
+ * Environment variable read by the shell wrapper to tee live output into the temporary runtime log file.
47205
+ */
47206
+ const PTBK_CODER_LOG_FILE_ENV_NAME = 'PTBK_CODER_LOG_FILE';
47207
+ /**
47208
+ * Small bash wrapper that preserves stdout/stderr streams while teeing both into the runtime log file.
47209
+ */
47210
+ const LOGGED_BASH_WRAPPER_COMMAND = `
47211
+ if [ -n "\${${PTBK_CODER_LOG_FILE_ENV_NAME}:-}" ]; then
47212
+ exec > >(tee -a "\$${PTBK_CODER_LOG_FILE_ENV_NAME}") 2> >(tee -a "\$${PTBK_CODER_LOG_FILE_ENV_NAME}" >&2)
47213
+ fi
47214
+ bash "$1"
47215
+ `.trim();
47216
+ /**
47217
+ * Shapes one bash invocation that optionally mirrors live script output into a temporary log file.
47218
+ */
47219
+ function buildLoggedBashExecution(scriptPath, logPath) {
47220
+ return {
47221
+ args: ['-lc', LOGGED_BASH_WRAPPER_COMMAND, 'ptbk-coder-temp-script', toPosixPath(scriptPath)],
47222
+ env: logPath ? { [PTBK_CODER_LOG_FILE_ENV_NAME]: toPosixPath(logPath) } : undefined,
47223
+ };
47224
+ }
47225
+ /**
47226
+ * Appends one execution-start section with the raw script input before the shell begins producing output.
47227
+ */
47228
+ async function appendScriptExecutionLogStart({ scriptPath, scriptContent, logPath, }) {
47229
+ if (!logPath) {
47230
+ return;
47231
+ }
47232
+ await mkdir(dirname(logPath), { recursive: true });
47233
+ const scriptKind = describeTempScriptKind(scriptPath);
47234
+ const normalizedInput = scriptContent.replace(/\r\n/g, '\n').trimEnd();
47235
+ const logSection = [
47236
+ `=== ${scriptKind} started at ${new Date().toISOString()} ===`,
47237
+ `Script path: ${toPosixPath(scriptPath)}`,
47238
+ '',
47239
+ '--- raw input ---',
47240
+ normalizedInput,
47241
+ '',
47242
+ '--- raw output ---',
47243
+ '',
47244
+ ].join('\n');
47245
+ await appendFile(logPath, `${logSection}\n`, 'utf-8');
47246
+ }
47247
+ /**
47248
+ * Appends one execution-finish section after the shell settles.
47249
+ */
47250
+ async function appendScriptExecutionLogFinish({ scriptPath, logPath, status, details, }) {
47251
+ if (!logPath) {
47252
+ return;
47253
+ }
47254
+ const scriptKind = describeTempScriptKind(scriptPath);
47255
+ const logLines = [
47256
+ '',
47257
+ `=== ${scriptKind} finished at ${new Date().toISOString()} ===`,
47258
+ `Status: ${status}`,
47259
+ ];
47260
+ if (details !== undefined) {
47261
+ logLines.push('');
47262
+ logLines.push('--- details ---');
47263
+ logLines.push(formatUnknownErrorDetails(details));
47264
+ }
47265
+ logLines.push('');
47266
+ await appendFile(logPath, `${logLines.join('\n')}\n`, 'utf-8');
47267
+ }
47268
+ /**
47269
+ * Distinguishes prompt-runner and verification temp shells in the shared runtime log.
47270
+ */
47271
+ function describeTempScriptKind(scriptPath) {
47272
+ return scriptPath.toLowerCase().endsWith('.test.sh') ? 'test shell' : 'runner shell';
47273
+ }
47274
+
47275
+ /**
47276
+ * Runs one temporary bash script, optionally mirroring its raw input/output into a live runtime log file.
47277
+ */
47278
+ async function runBashScriptWithOutput(options) {
47279
+ await appendScriptExecutionLogStart(options);
47280
+ const bashExecution = buildLoggedBashExecution(options.scriptPath, options.logPath);
47281
+ const scriptPathPosix = toPosixPath(options.scriptPath);
47282
+ return await new Promise((resolve, reject) => {
47283
+ const commandProcess = spawn('bash', bashExecution.args, {
47284
+ env: bashExecution.env ? { ...process.env, ...bashExecution.env } : process.env,
47285
+ });
47286
+ let output = '';
47287
+ let settled = false;
47288
+ let isSettling = false;
47289
+ /**
47290
+ * Appends the final log footer before settling.
47291
+ */
47292
+ const finishLog = async (status, details) => {
47293
+ await appendScriptExecutionLogFinish({
47294
+ scriptPath: options.scriptPath,
47295
+ logPath: options.logPath,
47296
+ status,
47297
+ details,
47298
+ });
47299
+ };
47300
+ /**
47301
+ * Ensures the promise settles only once.
47302
+ */
47303
+ const settleOnce = (handler) => {
47304
+ if (settled) {
47305
+ return;
47306
+ }
47307
+ settled = true;
47308
+ handler();
47309
+ };
47310
+ /**
47311
+ * Appends the final log footer and settles the promise exactly once.
47312
+ */
47313
+ const settleWithLog = (status, handler, details) => {
47314
+ if (isSettling || settled) {
47315
+ return;
47316
+ }
47317
+ isSettling = true;
47318
+ void finishLog(status, details).finally(() => {
47319
+ settleOnce(handler);
47320
+ });
47321
+ };
47322
+ commandProcess.stdout.on('data', (stdout) => {
47323
+ const chunk = stdout.toString();
47324
+ output += chunk;
47325
+ console.info(chunk);
47326
+ });
47327
+ commandProcess.stderr.on('data', (stderr) => {
47328
+ const chunk = stderr.toString();
47329
+ output += chunk;
47330
+ if (chunk.trim()) {
47331
+ console.warn(chunk);
47332
+ }
47333
+ });
47334
+ /**
47335
+ * Handles process exit and resolves or rejects accordingly.
47336
+ */
47337
+ const handleExit = (code) => {
47338
+ if (code === 0) {
47339
+ settleWithLog('succeeded', () => resolve(spaceTrim$1(output)));
47340
+ return;
47341
+ }
47342
+ const failure = new Error(spaceTrim$1(output) || `Command "bash ${scriptPathPosix}" exited with code ${code}`);
47343
+ settleWithLog(`failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}`, () => reject(failure), failure);
47344
+ };
47345
+ commandProcess.on('close', handleExit);
47346
+ commandProcess.on('exit', handleExit);
47347
+ commandProcess.on('disconnect', () => {
47348
+ const failure = new Error(`Command "bash ${scriptPathPosix}" disconnected`);
47349
+ settleWithLog('failed after disconnect', () => reject(failure), failure);
47350
+ });
47351
+ commandProcess.on('error', (error) => {
47352
+ const failure = new Error(`Command "bash ${scriptPathPosix}" failed: ${error.message}`);
47353
+ settleWithLog('failed before completion', () => reject(failure), failure);
47354
+ });
47355
+ });
47356
+ }
47357
+
47358
+ /**
47359
+ * Creates a temporary script file, runs a handler, and either cleans it up immediately or defers cleanup to the round tracker.
47056
47360
  */
47057
47361
  async function withTempScript(options, handler) {
47058
- const { scriptPath, scriptContent } = options;
47362
+ const { scriptPath, scriptContent, promptRoundArtifacts } = options;
47059
47363
  await mkdir(dirname$1(scriptPath), { recursive: true });
47060
47364
  await writeFile(scriptPath, scriptContent, 'utf-8');
47061
- const result = await handler(scriptPath);
47062
- await unlink(scriptPath).catch(() => undefined);
47063
- return result;
47365
+ promptRoundArtifacts === null || promptRoundArtifacts === void 0 ? void 0 : promptRoundArtifacts.track(scriptPath, getPromptRoundArtifactKindFromScriptPath(scriptPath));
47366
+ try {
47367
+ return await handler(scriptPath);
47368
+ }
47369
+ finally {
47370
+ if (!promptRoundArtifacts) {
47371
+ await unlink(scriptPath).catch(() => undefined);
47372
+ }
47373
+ }
47064
47374
  }
47065
47375
 
47066
47376
  /**
47067
- * Creates a temporary script file, runs it, captures output, and then deletes it.
47377
+ * Creates a temporary script file, runs it, captures output, and cleans it up immediately unless a round tracker defers that cleanup.
47068
47378
  */
47069
47379
  async function $runGoScriptWithOutput(options) {
47070
47380
  return await withTempScript(options, async (scriptPath) => {
47071
- return await $execCommand({
47072
- command: `bash "${toPosixPath(scriptPath)}"`,
47073
- isVerbose: true, // <- Note: Proxy the raw command output to the console
47381
+ return await runBashScriptWithOutput({
47382
+ ...options,
47383
+ scriptPath,
47074
47384
  });
47075
47385
  });
47076
47386
  }
@@ -47166,6 +47476,8 @@ class ClaudeCodeRunner {
47166
47476
  const output = await $runGoScriptWithOutput({
47167
47477
  scriptPath: options.scriptPath,
47168
47478
  scriptContent,
47479
+ logPath: options.logPath,
47480
+ promptRoundArtifacts: options.promptRoundArtifacts,
47169
47481
  });
47170
47482
  const usage = parseClaudeCodeJsonOutput(output);
47171
47483
  return { usage };
@@ -47173,13 +47485,13 @@ class ClaudeCodeRunner {
47173
47485
  }
47174
47486
 
47175
47487
  /**
47176
- * Creates a temporary script file, runs it, and then deletes it.
47488
+ * Creates a temporary script file, runs it, and cleans it up immediately unless a round tracker defers that cleanup.
47177
47489
  */
47178
47490
  async function $runGoScript(options) {
47179
47491
  await withTempScript(options, async (scriptPath) => {
47180
- await $execCommand({
47181
- command: `bash "${toPosixPath(scriptPath)}"`,
47182
- isVerbose: true, // <- Note: Proxy the raw command output to the console
47492
+ await runBashScriptWithOutput({
47493
+ ...options,
47494
+ scriptPath,
47183
47495
  });
47184
47496
  });
47185
47497
  }
@@ -47228,6 +47540,8 @@ class ClineRunner {
47228
47540
  await $runGoScript({
47229
47541
  scriptPath: options.scriptPath,
47230
47542
  scriptContent,
47543
+ logPath: options.logPath,
47544
+ promptRoundArtifacts: options.promptRoundArtifacts,
47231
47545
  });
47232
47546
  return { usage: UNCERTAIN_USAGE };
47233
47547
  }
@@ -47351,6 +47665,8 @@ class GeminiRunner {
47351
47665
  const output = await $runGoScriptWithOutput({
47352
47666
  scriptPath: options.scriptPath,
47353
47667
  scriptContent,
47668
+ logPath: options.logPath,
47669
+ promptRoundArtifacts: options.promptRoundArtifacts,
47354
47670
  });
47355
47671
  const usage = parseGeminiUsageFromOutput(output, options.prompt, this.options.model);
47356
47672
  return { usage };
@@ -47406,6 +47722,8 @@ class GitHubCopilotRunner {
47406
47722
  await $runGoScript({
47407
47723
  scriptPath: options.scriptPath,
47408
47724
  scriptContent,
47725
+ logPath: options.logPath,
47726
+ promptRoundArtifacts: options.promptRoundArtifacts,
47409
47727
  });
47410
47728
  return { usage: UNCERTAIN_USAGE };
47411
47729
  }
@@ -47442,14 +47760,30 @@ function buildCommandFailureMessage(scriptPathPosix, code, fullOutput) {
47442
47760
  async function runScriptUntilMarkerIdle(options) {
47443
47761
  const { scriptPath, completionLineMatcher, idleTimeoutMs } = options;
47444
47762
  const scriptPathPosix = toPosixPath(scriptPath);
47763
+ await appendScriptExecutionLogStart(options);
47764
+ const bashExecution = buildLoggedBashExecution(scriptPath, options.logPath);
47445
47765
  return await new Promise((resolve, reject) => {
47446
- const commandProcess = spawn('bash', [scriptPathPosix], { env: process.env });
47766
+ const commandProcess = spawn('bash', bashExecution.args, {
47767
+ env: bashExecution.env ? { ...process.env, ...bashExecution.env } : process.env,
47768
+ });
47447
47769
  let stdoutBuffer = '';
47448
47770
  let stderrBuffer = '';
47449
47771
  let fullOutput = '';
47450
47772
  let markerSeen = false;
47451
47773
  let idleTimer;
47452
47774
  let settled = false;
47775
+ let isSettling = false;
47776
+ /**
47777
+ * Appends the final log footer before settling.
47778
+ */
47779
+ const finishLog = async (status, details) => {
47780
+ await appendScriptExecutionLogFinish({
47781
+ scriptPath,
47782
+ logPath: options.logPath,
47783
+ status,
47784
+ details,
47785
+ });
47786
+ };
47453
47787
  /**
47454
47788
  * Ensures the promise settles only once.
47455
47789
  */
@@ -47464,6 +47798,18 @@ async function runScriptUntilMarkerIdle(options) {
47464
47798
  }
47465
47799
  handler();
47466
47800
  };
47801
+ /**
47802
+ * Appends the final log footer and settles the promise exactly once.
47803
+ */
47804
+ const settleWithLog = (status, handler, details) => {
47805
+ if (isSettling || settled) {
47806
+ return;
47807
+ }
47808
+ isSettling = true;
47809
+ void finishLog(status, details).finally(() => {
47810
+ settleOnce(handler);
47811
+ });
47812
+ };
47467
47813
  /**
47468
47814
  * Resets the idle timer that triggers termination after inactivity.
47469
47815
  */
@@ -47473,7 +47819,7 @@ async function runScriptUntilMarkerIdle(options) {
47473
47819
  }
47474
47820
  idleTimer = setTimeout(() => {
47475
47821
  commandProcess.kill();
47476
- settleOnce(() => resolve(fullOutput));
47822
+ settleWithLog('completed after idle timeout', () => resolve(fullOutput));
47477
47823
  }, idleTimeoutMs);
47478
47824
  };
47479
47825
  /**
@@ -47527,41 +47873,43 @@ async function runScriptUntilMarkerIdle(options) {
47527
47873
  * Handles process exit and resolves or rejects accordingly.
47528
47874
  */
47529
47875
  const handleExit = (code) => {
47530
- settleOnce(() => {
47531
- if (code === 0 || markerSeen) {
47876
+ const failure = code === 0 || markerSeen ? undefined : new Error(buildCommandFailureMessage(scriptPathPosix, code, fullOutput));
47877
+ const status = failure ? `failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}` : 'succeeded';
47878
+ settleWithLog(status, () => {
47879
+ if (!failure) {
47532
47880
  resolve(fullOutput);
47533
47881
  return;
47534
47882
  }
47535
- reject(new Error(buildCommandFailureMessage(scriptPathPosix, code, fullOutput)));
47883
+ reject(failure);
47536
47884
  });
47537
47885
  };
47538
47886
  commandProcess.on('close', handleExit);
47539
47887
  commandProcess.on('exit', handleExit);
47540
47888
  commandProcess.on('disconnect', () => {
47541
- settleOnce(() => {
47542
- reject(new Error(buildCommandFailureMessage(scriptPathPosix, null, fullOutput)));
47543
- });
47889
+ const failure = new Error(buildCommandFailureMessage(scriptPathPosix, null, fullOutput));
47890
+ settleWithLog('failed after disconnect', () => reject(failure), failure);
47544
47891
  });
47545
47892
  commandProcess.on('error', (error) => {
47546
- settleOnce(() => {
47547
- const outputSnippet = createOutputSnippet(fullOutput);
47548
- const details = outputSnippet ? `\n\n${outputSnippet}` : '';
47549
- reject(new Error(`Command "bash ${scriptPathPosix}" failed: ${error.message}${details}`));
47550
- });
47893
+ const outputSnippet = createOutputSnippet(fullOutput);
47894
+ const details = outputSnippet ? `\n\n${outputSnippet}` : '';
47895
+ const failure = new Error(`Command "bash ${scriptPathPosix}" failed: ${error.message}${details}`);
47896
+ settleWithLog('failed before completion', () => reject(failure), failure);
47551
47897
  });
47552
47898
  });
47553
47899
  }
47554
47900
 
47555
47901
  /**
47556
- * Creates a temporary script file, runs it, waits for a completion marker and idle time, and then deletes it.
47902
+ * Creates a temporary script file, runs it, waits for a completion marker and idle time, and defers cleanup when a round tracker is provided.
47557
47903
  * Returns the captured output for post-processing.
47558
47904
  */
47559
47905
  async function $runGoScriptUntilMarkerIdle(options) {
47560
47906
  return await withTempScript(options, async (scriptPath) => {
47561
47907
  return await runScriptUntilMarkerIdle({
47562
47908
  scriptPath,
47909
+ scriptContent: options.scriptContent,
47563
47910
  completionLineMatcher: options.completionLineMatcher,
47564
47911
  idleTimeoutMs: options.idleTimeoutMs,
47912
+ logPath: options.logPath,
47565
47913
  });
47566
47914
  });
47567
47915
  }
@@ -47939,6 +48287,8 @@ class OpenAiCodexRunner {
47939
48287
  scriptContent,
47940
48288
  completionLineMatcher: CODEX_COMPLETION_LINE,
47941
48289
  idleTimeoutMs: CODEX_COMPLETION_IDLE_MS,
48290
+ logPath: options.logPath,
48291
+ promptRoundArtifacts: options.promptRoundArtifacts,
47942
48292
  });
47943
48293
  this.rateLimitBackoff.reset();
47944
48294
  return { usage: buildCodexUsageFromOutput(output, this.options.model) };
@@ -48072,6 +48422,8 @@ class OpencodeRunner {
48072
48422
  output = await $runGoScriptWithOutput({
48073
48423
  scriptPath: options.scriptPath,
48074
48424
  scriptContent,
48425
+ logPath: options.logPath,
48426
+ promptRoundArtifacts: options.promptRoundArtifacts,
48075
48427
  });
48076
48428
  }
48077
48429
  catch (error) {
@@ -48098,6 +48450,7 @@ async function runPromptTestCommand(options) {
48098
48450
  cd "${projectPath}"
48099
48451
  ${options.command}
48100
48452
  `),
48453
+ logPath: options.logPath,
48101
48454
  });
48102
48455
  }
48103
48456
 
@@ -48121,6 +48474,8 @@ async function runPromptWithTestFeedback(options) {
48121
48474
  prompt: options.prompt,
48122
48475
  scriptPath: options.scriptPath,
48123
48476
  projectPath: options.projectPath,
48477
+ logPath: options.logPath,
48478
+ promptRoundArtifacts: options.promptRoundArtifacts,
48124
48479
  });
48125
48480
  return { ...result, attemptCount: 1 };
48126
48481
  }
@@ -48132,6 +48487,8 @@ async function runPromptWithTestFeedback(options) {
48132
48487
  prompt: promptForCurrentAttempt,
48133
48488
  scriptPath: options.scriptPath,
48134
48489
  projectPath: options.projectPath,
48490
+ logPath: options.logPath,
48491
+ promptRoundArtifacts: options.promptRoundArtifacts,
48135
48492
  });
48136
48493
  console.info(colors.gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
48137
48494
  try {
@@ -48139,6 +48496,7 @@ async function runPromptWithTestFeedback(options) {
48139
48496
  command: normalizedTestCommand,
48140
48497
  projectPath: options.projectPath,
48141
48498
  scriptPath: buildPromptTestScriptPath(options.scriptPath),
48499
+ logPath: options.logPath,
48142
48500
  });
48143
48501
  return { ...result, attemptCount };
48144
48502
  }
@@ -48976,6 +49334,7 @@ async function runCodexPrompts(providedOptions) {
48976
49334
  const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
48977
49335
  const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
48978
49336
  const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
49337
+ const promptRoundArtifacts = createCoderRunPromptRoundArtifacts(options.preserveLogs);
48979
49338
  if (isUiMode) {
48980
49339
  uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
48981
49340
  uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
@@ -48986,57 +49345,68 @@ async function runCodexPrompts(providedOptions) {
48986
49345
  }
48987
49346
  const promptExecutionStartedDate = moment();
48988
49347
  let attemptCount = 1;
49348
+ let promptRoundOutcome = 'failure';
48989
49349
  const roundChangedFilesSnapshot = options.normalizeLineEndings
48990
49350
  ? await captureChangedFilesSnapshot(process.cwd())
48991
49351
  : undefined;
48992
49352
  try {
48993
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
48994
- const result = await runPromptWithTestFeedback({
48995
- runner,
48996
- prompt: codexPrompt,
48997
- scriptPath,
48998
- projectPath: process.cwd(),
48999
- promptLabel,
49000
- testCommand: options.testCommand,
49001
- onAttemptStarted: (nextAttemptCount) => {
49002
- attemptCount = nextAttemptCount;
49003
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
49004
- if (nextAttemptCount > 1) {
49005
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
49006
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
49353
+ await withPromptRuntimeLog(scriptPath, async (logPath) => {
49354
+ try {
49355
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
49356
+ const result = await runPromptWithTestFeedback({
49357
+ runner,
49358
+ prompt: codexPrompt,
49359
+ scriptPath,
49360
+ projectPath: process.cwd(),
49361
+ promptLabel,
49362
+ testCommand: options.testCommand,
49363
+ logPath,
49364
+ promptRoundArtifacts,
49365
+ onAttemptStarted: (nextAttemptCount) => {
49366
+ attemptCount = nextAttemptCount;
49367
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
49368
+ if (nextAttemptCount > 1) {
49369
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
49370
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
49371
+ }
49372
+ },
49373
+ });
49374
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
49375
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
49376
+ markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
49377
+ await writePromptFile(nextPrompt.file);
49378
+ await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
49379
+ if (options.waitForUser) {
49380
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
49381
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Waiting... Press Enter to commit');
49382
+ printCommitMessage(commitMessage);
49383
+ await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
49384
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
49007
49385
  }
49008
- },
49009
- });
49010
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
49011
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
49012
- markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
49013
- await writePromptFile(nextPrompt.file);
49014
- await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
49015
- if (options.waitForUser) {
49016
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
49017
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Waiting... Press Enter to commit');
49018
- printCommitMessage(commitMessage);
49019
- await waitForEnter(colors.bgWhite('Press Enter to commit and continue...'));
49020
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
49021
- }
49022
- await commitChanges(commitMessage, { autoPush: options.autoPush });
49023
- await runPostPromptAutoMigrationIfEnabled(options);
49386
+ await commitChanges(commitMessage, { autoPush: options.autoPush });
49387
+ await runPostPromptAutoMigrationIfEnabled(options);
49388
+ promptRoundOutcome = 'success';
49389
+ }
49390
+ catch (error) {
49391
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
49392
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
49393
+ uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
49394
+ markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
49395
+ await writePromptFile(nextPrompt.file);
49396
+ await writePromptErrorLog({
49397
+ file: nextPrompt.file,
49398
+ section: nextPrompt.section,
49399
+ runnerName: runnerMetadata.runnerName,
49400
+ modelName: runnerMetadata.modelName,
49401
+ error,
49402
+ });
49403
+ await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
49404
+ throw error;
49405
+ }
49406
+ }, promptRoundArtifacts);
49024
49407
  }
49025
- catch (error) {
49026
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
49027
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
49028
- uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
49029
- markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
49030
- await writePromptFile(nextPrompt.file);
49031
- await writePromptErrorLog({
49032
- file: nextPrompt.file,
49033
- section: nextPrompt.section,
49034
- runnerName: runnerMetadata.runnerName,
49035
- modelName: runnerMetadata.modelName,
49036
- error,
49037
- });
49038
- await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
49039
- throw error;
49408
+ finally {
49409
+ await promptRoundArtifacts.cleanup(promptRoundOutcome);
49040
49410
  }
49041
49411
  }
49042
49412
  }