@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.
- package/esm/index.es.js +481 -111
- package/esm/index.es.js.map +1 -1
- 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/PromptRoundArtifacts.d.ts +35 -0
- 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/withPromptRuntimeLog.d.ts +5 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -0
- package/esm/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/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +480 -110
- package/umd/index.umd.js.map +1 -1
- 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/PromptRoundArtifacts.d.ts +35 -0
- 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/withPromptRuntimeLog.d.ts +5 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/withTempScript.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -0
- package/umd/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/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-
|
|
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
|
|
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.
|
|
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
|
|
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 '
|
|
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
|
-
|
|
21888
|
+
Deprecated legacy commitment that defines who the agent is, their background, expertise, and personality traits.
|
|
21882
21889
|
|
|
21883
|
-
##
|
|
21890
|
+
## Migration
|
|
21884
21891
|
|
|
21885
|
-
-
|
|
21886
|
-
-
|
|
21887
|
-
-
|
|
21888
|
-
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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 =
|
|
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
|
-
*
|
|
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
|
|
42213
|
-
let
|
|
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
|
|
42216
|
-
|
|
42272
|
+
if (commitment.type === 'GOAL' || commitment.type === 'GOALS') {
|
|
42273
|
+
goalDescription = commitment.content;
|
|
42274
|
+
hasGoalDescription = true;
|
|
42217
42275
|
}
|
|
42218
|
-
if (
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
-
|
|
47062
|
-
|
|
47063
|
-
|
|
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
|
|
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
|
|
47072
|
-
|
|
47073
|
-
|
|
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
|
|
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
|
|
47181
|
-
|
|
47182
|
-
|
|
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',
|
|
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
|
-
|
|
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
|
-
|
|
47531
|
-
|
|
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(
|
|
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
|
-
|
|
47542
|
-
|
|
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
|
-
|
|
47547
|
-
|
|
47548
|
-
|
|
47549
|
-
|
|
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
|
|
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
|
-
|
|
48994
|
-
|
|
48995
|
-
|
|
48996
|
-
|
|
48997
|
-
|
|
48998
|
-
|
|
48999
|
-
|
|
49000
|
-
|
|
49001
|
-
|
|
49002
|
-
|
|
49003
|
-
|
|
49004
|
-
|
|
49005
|
-
|
|
49006
|
-
|
|
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
|
-
|
|
49011
|
-
|
|
49012
|
-
|
|
49013
|
-
|
|
49014
|
-
|
|
49015
|
-
|
|
49016
|
-
|
|
49017
|
-
|
|
49018
|
-
|
|
49019
|
-
|
|
49020
|
-
|
|
49021
|
-
|
|
49022
|
-
|
|
49023
|
-
|
|
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
|
-
|
|
49026
|
-
|
|
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
|
}
|