@promptbook/cli 0.112.0-41 → 0.112.0-43
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/README.md +10 -3
- package/esm/apps/agents-server/src/database/acquireMigrationExecutionLock.d.ts +12 -1
- package/esm/apps/agents-server/src/database/runDatabaseMigrations.d.ts +9 -0
- package/esm/index.es.js +1218 -114
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/formatUnknownErrorDetails.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/common/waitForPause.d.ts +21 -1
- package/esm/scripts/run-codex-prompts/git/commitChanges.d.ts +2 -2
- package/esm/scripts/run-codex-prompts/prompts/formatPromptAttemptMetadata.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/prompts/markPromptDone.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/markPromptFailed.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +13 -0
- package/esm/scripts/run-codex-prompts/testing/runPromptWithTestFeedback.d.ts +25 -0
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +112 -0
- package/esm/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +30 -0
- package/esm/scripts/verify-prompts/verify-prompts.d.ts +23 -2
- package/esm/src/book-components/Chat/Chat/ChatProps.d.ts +1 -1
- package/esm/src/cli/cli-commands/coder/getTypescriptModule.d.ts +19 -0
- package/esm/src/cli/cli-commands/coder/getTypescriptModule.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/mergeStringRecordJsonFile.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/verify.test.d.ts +1 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +2 -14
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.d.ts +40 -0
- package/esm/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.test.d.ts +1 -0
- package/esm/src/llm-providers/agent/Agent.test.d.ts +1 -0
- package/esm/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +4 -0
- package/esm/src/llm-providers/agent/AgentOptions.d.ts +8 -0
- package/esm/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +9 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +3 -2
- package/umd/apps/agents-server/src/database/acquireMigrationExecutionLock.d.ts +12 -1
- package/umd/apps/agents-server/src/database/runDatabaseMigrations.d.ts +9 -0
- package/umd/index.umd.js +1221 -118
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/formatUnknownErrorDetails.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/common/waitForPause.d.ts +21 -1
- package/umd/scripts/run-codex-prompts/git/commitChanges.d.ts +2 -2
- package/umd/scripts/run-codex-prompts/prompts/formatPromptAttemptMetadata.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/prompts/markPromptDone.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/markPromptFailed.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +13 -0
- package/umd/scripts/run-codex-prompts/testing/runPromptWithTestFeedback.d.ts +25 -0
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +112 -0
- package/umd/scripts/run-codex-prompts/ui/renderCoderRunUi.d.ts +30 -0
- package/umd/scripts/verify-prompts/verify-prompts.d.ts +23 -2
- package/umd/src/book-components/Chat/Chat/ChatProps.d.ts +1 -1
- package/umd/src/cli/cli-commands/coder/getTypescriptModule.d.ts +19 -0
- package/umd/src/cli/cli-commands/coder/getTypescriptModule.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/mergeStringRecordJsonFile.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/verify.test.d.ts +1 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/AgentCollectionInSupabase.d.ts +2 -14
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.d.ts +40 -0
- package/umd/src/collection/agent-collection/constructors/agent-collection-in-supabase/createAgentPersistenceRecords.test.d.ts +1 -0
- package/umd/src/llm-providers/agent/Agent.test.d.ts +1 -0
- package/umd/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +4 -0
- package/umd/src/llm-providers/agent/AgentOptions.d.ts +8 -0
- package/umd/src/llm-providers/agent/CreateAgentLlmExecutionToolsOptions.d.ts +9 -0
- package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('fs'), require('path'), require('fs/promises'), require('waitasecond'), require('prompts'), require('dotenv'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('socket.io-client'), require('crypto-js'), require('jszip'), require('crypto'), require('@mozilla/readability'), require('jsdom'), require('showdown'), require('glob-promise'), require('moment'), require('express'), require('express-openapi-validator'), require('http'), require('socket.io'), require('swagger-ui-express'), require('react'), require('react-dom/server'), require('@anthropic-ai/sdk'), require('bottleneck'), require('@azure/openai'), require('typescript'), require('ignore'), require('readline'), require('child_process'), require('pg'), require('@supabase/supabase-js'), require('path/posix'), require('rxjs'), require('mime-types'), require('papaparse'), require('@openai/agents'), require('openai')) :
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'fs', 'path', 'fs/promises', 'waitasecond', 'prompts', 'dotenv', 'crypto-js/enc-hex', 'crypto-js/sha256', 'socket.io-client', 'crypto-js', 'jszip', 'crypto', '@mozilla/readability', 'jsdom', 'showdown', 'glob-promise', 'moment', 'express', 'express-openapi-validator', 'http', 'socket.io', 'swagger-ui-express', 'react', 'react-dom/server', '@anthropic-ai/sdk', 'bottleneck', '@azure/openai', 'typescript', 'ignore', 'readline', 'child_process', 'pg', '@supabase/supabase-js', 'path/posix', 'rxjs', 'mime-types', 'papaparse', '@openai/agents', 'openai'], factory) :
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global._spaceTrim, global.fs, global.path, global.promises, global.waitasecond, global.prompts, global.dotenv, global.hexEncoder, global.sha256, global.socket_ioClient, global.cryptoJs, global.JSZip, global.crypto, global.readability, global.jsdom, global.showdown, global.glob, global.moment, global.express, global.OpenApiValidator, global.http, global.socket_io, global.swaggerUi, global.react, global.server, global.Anthropic, global.Bottleneck, global.openai, global.ts, global.ignore, global.readline, global.child_process, global.pg, null, global.posix, global.rxjs, global.mimeTypes, global.papaparse, global.agents, global.OpenAI));
|
|
5
|
-
})(this, (function (exports, colors, commander, _spaceTrim, fs, path, promises, waitasecond, prompts, dotenv, hexEncoder, sha256, socket_ioClient, cryptoJs, JSZip, crypto, readability, jsdom, showdown, glob, moment, express, OpenApiValidator, http, socket_io, swaggerUi, react, server, Anthropic, Bottleneck, openai, ts, ignore, readline, child_process, pg, supabaseJs, posix, rxjs, mimeTypes, papaparse, agents, OpenAI) { 'use strict';
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('fs'), require('path'), require('fs/promises'), require('waitasecond'), require('prompts'), require('dotenv'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('socket.io-client'), require('crypto-js'), require('jszip'), require('crypto'), require('@mozilla/readability'), require('jsdom'), require('showdown'), require('glob-promise'), require('moment'), require('express'), require('express-openapi-validator'), require('http'), require('socket.io'), require('swagger-ui-express'), require('react'), require('react-dom/server'), require('@anthropic-ai/sdk'), require('bottleneck'), require('@azure/openai'), require('typescript'), require('ignore'), require('readline'), require('child_process'), require('pg'), require('@supabase/supabase-js'), require('path/posix'), require('events'), require('rxjs'), require('mime-types'), require('papaparse'), require('@openai/agents'), require('openai')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'fs', 'path', 'fs/promises', 'waitasecond', 'prompts', 'dotenv', 'crypto-js/enc-hex', 'crypto-js/sha256', 'socket.io-client', 'crypto-js', 'jszip', 'crypto', '@mozilla/readability', 'jsdom', 'showdown', 'glob-promise', 'moment', 'express', 'express-openapi-validator', 'http', 'socket.io', 'swagger-ui-express', 'react', 'react-dom/server', '@anthropic-ai/sdk', 'bottleneck', '@azure/openai', 'typescript', 'ignore', 'readline', 'child_process', 'pg', '@supabase/supabase-js', 'path/posix', 'events', 'rxjs', 'mime-types', 'papaparse', '@openai/agents', 'openai'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global._spaceTrim, global.fs, global.path, global.promises, global.waitasecond, global.prompts, global.dotenv, global.hexEncoder, global.sha256, global.socket_ioClient, global.cryptoJs, global.JSZip, global.crypto, global.readability, global.jsdom, global.showdown, global.glob, global.moment, global.express, global.OpenApiValidator, global.http, global.socket_io, global.swaggerUi, global.react, global.server, global.Anthropic, global.Bottleneck, global.openai, global.ts, global.ignore, global.readline, global.child_process, global.pg, null, global.posix, global.events, global.rxjs, global.mimeTypes, global.papaparse, global.agents, global.OpenAI));
|
|
5
|
+
})(this, (function (exports, colors, commander, _spaceTrim, fs, path, promises, waitasecond, prompts, dotenv, hexEncoder, sha256, socket_ioClient, cryptoJs, JSZip, crypto, readability, jsdom, showdown, glob, moment, express, OpenApiValidator, http, socket_io, swaggerUi, react, server, Anthropic, Bottleneck, openai, ts, ignore, readline, child_process, pg, supabaseJs, posix, events, rxjs, mimeTypes, papaparse, agents, OpenAI) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
8
|
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
* @generated
|
|
61
61
|
* @see https://github.com/webgptorg/promptbook
|
|
62
62
|
*/
|
|
63
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-
|
|
63
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.112.0-43';
|
|
64
64
|
/**
|
|
65
65
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
66
66
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -2323,7 +2323,7 @@
|
|
|
2323
2323
|
'',
|
|
2324
2324
|
'## Customizing the workflow',
|
|
2325
2325
|
'- Edit `package.json` if you want `npm run coder:run` to use another coding agent, model, thinking level, context file, or wait mode.',
|
|
2326
|
-
'- Use direct CLI commands when you need one-off flags such as `--priority`, `--ignore-git-changes`, `--dry-run`, `--allow-credits`, or `--auto-migrate`.',
|
|
2326
|
+
'- Use direct CLI commands when you need one-off flags such as `--priority`, `--ignore-git-changes`, `--dry-run`, `--test`, `--allow-credits`, or `--auto-migrate`.',
|
|
2327
2327
|
'- Use `npx ptbk coder --help` and `npx ptbk coder <command> --help` for the full CLI reference.',
|
|
2328
2328
|
].join('\n');
|
|
2329
2329
|
}
|
|
@@ -2583,6 +2583,26 @@
|
|
|
2583
2583
|
}
|
|
2584
2584
|
// TODO: Maybe split `ParseError` and `ApplyError`
|
|
2585
2585
|
|
|
2586
|
+
/**
|
|
2587
|
+
* Loads the TypeScript runtime used for parsing JSONC-style project files.
|
|
2588
|
+
*
|
|
2589
|
+
* @private internal utility of `coder init`
|
|
2590
|
+
*/
|
|
2591
|
+
async function getTypescriptModule() {
|
|
2592
|
+
return normalizeImportedTypescriptModule((await import('typescript')));
|
|
2593
|
+
}
|
|
2594
|
+
/**
|
|
2595
|
+
* Normalizes CommonJS-via-`default` and direct namespace imports of TypeScript.
|
|
2596
|
+
*
|
|
2597
|
+
* @private internal utility of `getTypescriptModule`
|
|
2598
|
+
*/
|
|
2599
|
+
function normalizeImportedTypescriptModule(importedTypescriptModule) {
|
|
2600
|
+
return 'parseConfigFileTextToJson' in importedTypescriptModule
|
|
2601
|
+
? importedTypescriptModule
|
|
2602
|
+
: importedTypescriptModule.default;
|
|
2603
|
+
}
|
|
2604
|
+
// Note: [🟡] Code for coder init TypeScript loading [getTypescriptModule](src/cli/cli-commands/coder/getTypescriptModule.ts) should never be published outside of `@promptbook/cli`
|
|
2605
|
+
|
|
2586
2606
|
/**
|
|
2587
2607
|
* Default indentation used when creating new JSON configuration files.
|
|
2588
2608
|
*/
|
|
@@ -2628,7 +2648,7 @@
|
|
|
2628
2648
|
if (fileContent.trim() === '') {
|
|
2629
2649
|
return {};
|
|
2630
2650
|
}
|
|
2631
|
-
const typescript = await
|
|
2651
|
+
const typescript = await getTypescriptModule();
|
|
2632
2652
|
const parsedFile = typescript.parseConfigFileTextToJson(relativeFilePath, fileContent);
|
|
2633
2653
|
if (parsedFile.error) {
|
|
2634
2654
|
throw new ParseError(_spaceTrim.spaceTrim(`
|
|
@@ -2986,7 +3006,9 @@
|
|
|
2986
3006
|
|
|
2987
3007
|
Features:
|
|
2988
3008
|
- Automatically stages and commits changes with agent identity
|
|
3009
|
+
- Optional post-commit git push with explicit --auto-push opt-in
|
|
2989
3010
|
- Supports GPG signing of commits
|
|
3011
|
+
- Optional post-prompt verification with test-feedback retries
|
|
2990
3012
|
- Progress tracking and interactive controls
|
|
2991
3013
|
- Dry-run mode to preview prompts
|
|
2992
3014
|
`));
|
|
@@ -2999,17 +3021,19 @@
|
|
|
2999
3021
|
Gemini examples: gemini-3-flash-preview, default
|
|
3000
3022
|
`));
|
|
3001
3023
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
3024
|
+
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
3002
3025
|
command.addOption(new commander.Option('--thinking-level <thinking-level>', `Set reasoning effort for supported runners (${THINKING_LEVEL_VALUES.join(', ')})`).choices([...THINKING_LEVEL_VALUES]));
|
|
3003
3026
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption, 0);
|
|
3004
3027
|
command.option('--no-wait', 'Skip user prompts between processing');
|
|
3005
3028
|
command.option('--ignore-git-changes', 'Skip clean working tree check before running prompts', false);
|
|
3006
3029
|
command.option('--allow-credits', 'Allow OpenAI Codex runner to spend credits when rate limits are exhausted', false);
|
|
3007
3030
|
command.option('--no-normalize-line-endings', 'Disable automatic LF normalization for files changed in each coding round');
|
|
3008
|
-
command.option('--
|
|
3031
|
+
command.option('--auto-push', 'Automatically git push after each commit', false);
|
|
3009
3032
|
command.option('--auto-migrate', 'Run testing-server database migrations automatically after each successfully processed prompt');
|
|
3010
3033
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
3011
3034
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
3012
|
-
const { dryRun, agent, model, context, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate,
|
|
3035
|
+
const { dryRun, agent, model, context, test, thinkingLevel, priority, wait, ignoreGitChanges, allowCredits, normalizeLineEndings, autoMigrate, allowDestructiveAutoMigrate, autoPush, } = cliOptions;
|
|
3036
|
+
const testCommand = normalizeCommandOptionValue(test);
|
|
3013
3037
|
// Validate agent
|
|
3014
3038
|
let agentName = undefined;
|
|
3015
3039
|
if (agent) {
|
|
@@ -3038,13 +3062,14 @@
|
|
|
3038
3062
|
agentName,
|
|
3039
3063
|
model,
|
|
3040
3064
|
context,
|
|
3065
|
+
testCommand,
|
|
3041
3066
|
thinkingLevel,
|
|
3042
3067
|
priority,
|
|
3043
3068
|
normalizeLineEndings,
|
|
3044
3069
|
allowCredits,
|
|
3045
3070
|
autoMigrate,
|
|
3046
3071
|
allowDestructiveAutoMigrate,
|
|
3047
|
-
|
|
3072
|
+
autoPush,
|
|
3048
3073
|
};
|
|
3049
3074
|
// Note: Import the function dynamically to avoid loading heavy dependencies until needed
|
|
3050
3075
|
const { runCodexPrompts } = await Promise.resolve().then(function () { return runCodexPrompts$1; });
|
|
@@ -3073,6 +3098,19 @@
|
|
|
3073
3098
|
}
|
|
3074
3099
|
return parsed;
|
|
3075
3100
|
}
|
|
3101
|
+
/**
|
|
3102
|
+
* Joins one Commander option that may be parsed either as a single string or a variadic token array.
|
|
3103
|
+
*
|
|
3104
|
+
* @private internal utility of `coder run` command
|
|
3105
|
+
*/
|
|
3106
|
+
function normalizeCommandOptionValue(value) {
|
|
3107
|
+
if (value === undefined) {
|
|
3108
|
+
return undefined;
|
|
3109
|
+
}
|
|
3110
|
+
const parts = Array.isArray(value) ? value : [value];
|
|
3111
|
+
const normalizedValue = parts.map((part) => part.trim()).filter(Boolean).join(' ').trim();
|
|
3112
|
+
return normalizedValue === '' ? undefined : normalizedValue;
|
|
3113
|
+
}
|
|
3076
3114
|
// Note: [🟡] Code for CLI command [run](src/cli/cli-commands/coder/run.ts) should never be published outside of `@promptbook/cli`
|
|
3077
3115
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3078
3116
|
|
|
@@ -3094,14 +3132,16 @@
|
|
|
3094
3132
|
- Archives verified prompt files to prompts/done/ directory
|
|
3095
3133
|
- Auto-appends repair prompts for incomplete work
|
|
3096
3134
|
- Processes files with all-done prompts first
|
|
3135
|
+
- Supports ignoring matching prompt candidates for one verification run
|
|
3097
3136
|
`));
|
|
3098
3137
|
command.option('--reverse', 'Process prompt files in reverse order', false);
|
|
3138
|
+
command.option('--ignore <candidate-text>', 'Ignore prompt files whose filename or first prompt line contains the given text (repeatable)', collectStringOption, []);
|
|
3099
3139
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
3100
|
-
const { reverse } = cliOptions;
|
|
3140
|
+
const { reverse, ignore } = cliOptions;
|
|
3101
3141
|
// Note: Import the main function dynamically to avoid loading heavy dependencies until needed
|
|
3102
3142
|
const { verifyPrompts } = await Promise.resolve().then(function () { return verifyPrompts$1; });
|
|
3103
3143
|
try {
|
|
3104
|
-
await verifyPrompts(reverse);
|
|
3144
|
+
await verifyPrompts({ reverse, ignore });
|
|
3105
3145
|
}
|
|
3106
3146
|
catch (error) {
|
|
3107
3147
|
console.error(colors__default["default"].bgRed('Prompt verification failed:'), error);
|
|
@@ -3110,6 +3150,14 @@
|
|
|
3110
3150
|
return process.exit(0);
|
|
3111
3151
|
}));
|
|
3112
3152
|
}
|
|
3153
|
+
/**
|
|
3154
|
+
* Collects repeatable string options from Commander.
|
|
3155
|
+
*
|
|
3156
|
+
* @private internal utility of `coder verify` command
|
|
3157
|
+
*/
|
|
3158
|
+
function collectStringOption(value, previousValues) {
|
|
3159
|
+
return [...previousValues, value];
|
|
3160
|
+
}
|
|
3113
3161
|
// Note: [🟡] Code for CLI command [verify](src/cli/cli-commands/coder/verify.ts) should never be published outside of `@promptbook/cli`
|
|
3114
3162
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3115
3163
|
|
|
@@ -22549,6 +22597,15 @@
|
|
|
22549
22597
|
* Map of team tool titles.
|
|
22550
22598
|
*/
|
|
22551
22599
|
const teamToolTitles = {};
|
|
22600
|
+
/**
|
|
22601
|
+
* Shared TEAM usage rules appended ahead of teammate listings.
|
|
22602
|
+
*
|
|
22603
|
+
* @private
|
|
22604
|
+
*/
|
|
22605
|
+
const TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES = [
|
|
22606
|
+
'- If a teammate is relevant to the request, consult that teammate using the matching tool.',
|
|
22607
|
+
'- Do not ask the user for information that a listed teammate can provide directly.',
|
|
22608
|
+
];
|
|
22552
22609
|
/**
|
|
22553
22610
|
* Constant for remote agents by Url.
|
|
22554
22611
|
*/
|
|
@@ -22638,12 +22695,9 @@
|
|
|
22638
22695
|
if (updatedTools.some((tool) => tool.name === entry.toolName)) {
|
|
22639
22696
|
continue;
|
|
22640
22697
|
}
|
|
22641
|
-
const toolDescription = entry.description
|
|
22642
|
-
? `Consult teammate ${entry.teammate.label}\n${entry.description}`
|
|
22643
|
-
: `Consult teammate ${entry.teammate.label}`;
|
|
22644
22698
|
updatedTools.push({
|
|
22645
22699
|
name: entry.toolName,
|
|
22646
|
-
description:
|
|
22700
|
+
description: buildTeamToolDescription(entry),
|
|
22647
22701
|
parameters: {
|
|
22648
22702
|
type: 'object',
|
|
22649
22703
|
properties: {
|
|
@@ -22712,22 +22766,72 @@
|
|
|
22712
22766
|
/**
|
|
22713
22767
|
* Builds the textual TEAM section body for the final system message.
|
|
22714
22768
|
*
|
|
22715
|
-
* Each teammate is listed with its tool name
|
|
22716
|
-
* Uses `spaceTrim` to ensure consistent whitespace and indentation.
|
|
22769
|
+
* Each teammate is listed with its tool name, TEAM instructions, and optional profile hints.
|
|
22717
22770
|
*/
|
|
22718
22771
|
function buildTeamSystemMessageBody(teamEntries) {
|
|
22719
|
-
const lines =
|
|
22720
|
-
|
|
22721
|
-
|
|
22722
|
-
|
|
22723
|
-
|
|
22724
|
-
|
|
22725
|
-
|
|
22726
|
-
|
|
22727
|
-
|
|
22728
|
-
});
|
|
22772
|
+
const lines = [
|
|
22773
|
+
...TEAM_SYSTEM_MESSAGE_GUIDANCE_LINES,
|
|
22774
|
+
'',
|
|
22775
|
+
...teamEntries.map((entry, index) => {
|
|
22776
|
+
const toolLine = `${index + 1}) ${entry.teammate.label} tool \`${entry.toolName}\``;
|
|
22777
|
+
const detailLines = collectTeamEntryDetails(entry).map(formatTeamEntryDetailLine);
|
|
22778
|
+
return [toolLine, ...detailLines].join('\n');
|
|
22779
|
+
}),
|
|
22780
|
+
];
|
|
22729
22781
|
return lines.join('\n');
|
|
22730
22782
|
}
|
|
22783
|
+
/**
|
|
22784
|
+
* Builds the model-visible description for one teammate tool.
|
|
22785
|
+
*
|
|
22786
|
+
* @private
|
|
22787
|
+
*/
|
|
22788
|
+
function buildTeamToolDescription(entry) {
|
|
22789
|
+
const detailLines = collectTeamEntryDetails(entry).map(({ label, content }) => `${label}: ${content}`);
|
|
22790
|
+
return [`Consult teammate ${entry.teammate.label}`, ...detailLines].join('\n');
|
|
22791
|
+
}
|
|
22792
|
+
/**
|
|
22793
|
+
* Collects structured teammate details that should stay visible to the model.
|
|
22794
|
+
*
|
|
22795
|
+
* @private
|
|
22796
|
+
*/
|
|
22797
|
+
function collectTeamEntryDetails(entry) {
|
|
22798
|
+
var _a;
|
|
22799
|
+
const details = [];
|
|
22800
|
+
const instructions = entry.teammate.instructions.trim();
|
|
22801
|
+
const description = ((_a = entry.description) === null || _a === void 0 ? void 0 : _a.trim()) || '';
|
|
22802
|
+
if (instructions) {
|
|
22803
|
+
details.push({
|
|
22804
|
+
label: 'TEAM instructions',
|
|
22805
|
+
content: instructions,
|
|
22806
|
+
});
|
|
22807
|
+
}
|
|
22808
|
+
if (description) {
|
|
22809
|
+
details.push({
|
|
22810
|
+
label: 'Profile',
|
|
22811
|
+
content: description,
|
|
22812
|
+
});
|
|
22813
|
+
}
|
|
22814
|
+
return details;
|
|
22815
|
+
}
|
|
22816
|
+
/**
|
|
22817
|
+
* Formats one teammate detail line for the TEAM system-message section.
|
|
22818
|
+
*
|
|
22819
|
+
* @private
|
|
22820
|
+
*/
|
|
22821
|
+
function formatTeamEntryDetailLine(detail) {
|
|
22822
|
+
return indentMultilineText(`${detail.label}: ${detail.content}`, ' ');
|
|
22823
|
+
}
|
|
22824
|
+
/**
|
|
22825
|
+
* Indents all lines of one potentially multi-line text block.
|
|
22826
|
+
*
|
|
22827
|
+
* @private
|
|
22828
|
+
*/
|
|
22829
|
+
function indentMultilineText(text, prefix) {
|
|
22830
|
+
return text
|
|
22831
|
+
.split('\n')
|
|
22832
|
+
.map((line) => `${prefix}${line}`)
|
|
22833
|
+
.join('\n');
|
|
22834
|
+
}
|
|
22731
22835
|
/**
|
|
22732
22836
|
* Registers tool function and title for a teammate tool.
|
|
22733
22837
|
*/
|
|
@@ -40900,7 +41004,7 @@
|
|
|
40900
41004
|
systemMessage: '',
|
|
40901
41005
|
promptSuffix: '',
|
|
40902
41006
|
// modelName: 'gpt-5',
|
|
40903
|
-
modelName: '
|
|
41007
|
+
modelName: 'gpt-5.4-mini',
|
|
40904
41008
|
temperature: 0.7,
|
|
40905
41009
|
topP: 0.9,
|
|
40906
41010
|
topK: 50,
|
|
@@ -44080,7 +44184,26 @@
|
|
|
44080
44184
|
/**
|
|
44081
44185
|
* CLI usage text for this script.
|
|
44082
44186
|
*/
|
|
44083
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--
|
|
44187
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--agent <agent-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--no-wait] [--ignore-git-changes] [--no-normalize-line-endings] [--auto-push]';
|
|
44188
|
+
/**
|
|
44189
|
+
* Top-level flags supported by this command.
|
|
44190
|
+
*/
|
|
44191
|
+
const KNOWN_OPTION_FLAGS = new Set([
|
|
44192
|
+
'--dry-run',
|
|
44193
|
+
'--agent',
|
|
44194
|
+
'--model',
|
|
44195
|
+
'--context',
|
|
44196
|
+
'--test',
|
|
44197
|
+
'--thinking-level',
|
|
44198
|
+
'--priority',
|
|
44199
|
+
'--allow-credits',
|
|
44200
|
+
'--auto-migrate',
|
|
44201
|
+
'--allow-destructive-auto-migrate',
|
|
44202
|
+
'--no-wait',
|
|
44203
|
+
'--ignore-git-changes',
|
|
44204
|
+
'--no-normalize-line-endings',
|
|
44205
|
+
'--auto-push',
|
|
44206
|
+
]);
|
|
44084
44207
|
/**
|
|
44085
44208
|
* Parses CLI arguments into runner options.
|
|
44086
44209
|
*/
|
|
@@ -44101,6 +44224,8 @@
|
|
|
44101
44224
|
}
|
|
44102
44225
|
const model = readOptionValue(args, '--model');
|
|
44103
44226
|
const context = readOptionValue(args, '--context');
|
|
44227
|
+
const hasTestCommandFlag = args.includes('--test');
|
|
44228
|
+
const testCommand = readVariadicOptionValue(args, '--test');
|
|
44104
44229
|
const hasThinkingLevelFlag = args.includes('--thinking-level');
|
|
44105
44230
|
const thinkingLevelValue = readOptionValue(args, '--thinking-level');
|
|
44106
44231
|
const hasPriorityFlag = args.includes('--priority');
|
|
@@ -44110,8 +44235,11 @@
|
|
|
44110
44235
|
const allowCredits = args.includes('--allow-credits');
|
|
44111
44236
|
const autoMigrate = args.includes('--auto-migrate');
|
|
44112
44237
|
const allowDestructiveAutoMigrate = args.includes('--allow-destructive-auto-migrate');
|
|
44113
|
-
const
|
|
44238
|
+
const autoPush = args.includes('--auto-push');
|
|
44114
44239
|
let thinkingLevel;
|
|
44240
|
+
if (hasTestCommandFlag && testCommand === undefined) {
|
|
44241
|
+
exitWithUsageError('Missing value for --test. Use a shell command such as `npm run test` and quote it when it contains top-level CLI flags.');
|
|
44242
|
+
}
|
|
44115
44243
|
if (hasThinkingLevelFlag && thinkingLevelValue === undefined) {
|
|
44116
44244
|
exitWithUsageError(`Missing value for --thinking-level. Use one of: ${THINKING_LEVEL_VALUES.join(', ')}.`);
|
|
44117
44245
|
}
|
|
@@ -44132,10 +44260,11 @@
|
|
|
44132
44260
|
allowCredits,
|
|
44133
44261
|
autoMigrate,
|
|
44134
44262
|
allowDestructiveAutoMigrate,
|
|
44135
|
-
|
|
44263
|
+
autoPush,
|
|
44136
44264
|
agentName,
|
|
44137
44265
|
model,
|
|
44138
44266
|
context,
|
|
44267
|
+
testCommand,
|
|
44139
44268
|
thinkingLevel,
|
|
44140
44269
|
priority,
|
|
44141
44270
|
};
|
|
@@ -44150,6 +44279,28 @@
|
|
|
44150
44279
|
const index = args.indexOf(flag);
|
|
44151
44280
|
return args[index + 1];
|
|
44152
44281
|
}
|
|
44282
|
+
/**
|
|
44283
|
+
* Reads a multi-token shell command value that follows a given flag.
|
|
44284
|
+
*/
|
|
44285
|
+
function readVariadicOptionValue(args, flag) {
|
|
44286
|
+
if (!args.includes(flag)) {
|
|
44287
|
+
return undefined;
|
|
44288
|
+
}
|
|
44289
|
+
const index = args.indexOf(flag);
|
|
44290
|
+
const valueParts = [];
|
|
44291
|
+
for (let i = index + 1; i < args.length; i++) {
|
|
44292
|
+
const valuePart = args[i];
|
|
44293
|
+
if (valuePart === undefined) {
|
|
44294
|
+
continue;
|
|
44295
|
+
}
|
|
44296
|
+
if (KNOWN_OPTION_FLAGS.has(valuePart)) {
|
|
44297
|
+
break;
|
|
44298
|
+
}
|
|
44299
|
+
valueParts.push(valuePart);
|
|
44300
|
+
}
|
|
44301
|
+
const normalizedValue = valueParts.join(' ').trim();
|
|
44302
|
+
return normalizedValue === '' ? undefined : normalizedValue;
|
|
44303
|
+
}
|
|
44153
44304
|
/**
|
|
44154
44305
|
* Parses and validates the minimum prompt priority.
|
|
44155
44306
|
*/
|
|
@@ -44175,6 +44326,21 @@
|
|
|
44175
44326
|
process.exit(1);
|
|
44176
44327
|
}
|
|
44177
44328
|
|
|
44329
|
+
/**
|
|
44330
|
+
* Appends optional coding context to a runner prompt.
|
|
44331
|
+
*/
|
|
44332
|
+
function appendCoderContext(prompt, context) {
|
|
44333
|
+
const normalizedContext = context === null || context === void 0 ? void 0 : context.trim();
|
|
44334
|
+
if (!normalizedContext) {
|
|
44335
|
+
return prompt;
|
|
44336
|
+
}
|
|
44337
|
+
const normalizedPrompt = prompt.trimEnd();
|
|
44338
|
+
if (normalizedPrompt === '') {
|
|
44339
|
+
return normalizedContext;
|
|
44340
|
+
}
|
|
44341
|
+
return `${normalizedPrompt}\n\n${normalizedContext}`;
|
|
44342
|
+
}
|
|
44343
|
+
|
|
44178
44344
|
/**
|
|
44179
44345
|
* Refresh interval for the progress header in milliseconds.
|
|
44180
44346
|
*/
|
|
@@ -44186,7 +44352,7 @@
|
|
|
44186
44352
|
/**
|
|
44187
44353
|
* Calendar formats used when displaying the estimated completion time.
|
|
44188
44354
|
*/
|
|
44189
|
-
const ESTIMATED_DONE_CALENDAR_FORMATS = {
|
|
44355
|
+
const ESTIMATED_DONE_CALENDAR_FORMATS$1 = {
|
|
44190
44356
|
sameDay: '[Today] h:mm',
|
|
44191
44357
|
nextDay: '[Tomorrow] h:mm',
|
|
44192
44358
|
nextWeek: 'dddd h:mm',
|
|
@@ -44285,15 +44451,15 @@
|
|
|
44285
44451
|
const sessionTotal = sessionDone + stats.forAgent;
|
|
44286
44452
|
const percentage = totalPrompts > 0 ? Math.round((completedPrompts / totalPrompts) * 100) : 0;
|
|
44287
44453
|
const elapsedDuration = moment__default["default"].duration(moment__default["default"]().diff(startTime));
|
|
44288
|
-
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
44454
|
+
const elapsedText = formatDurationBrief$1(elapsedDuration);
|
|
44289
44455
|
let estimatedTotalText = '—';
|
|
44290
44456
|
let estimatedLabel = 'unknown';
|
|
44291
44457
|
if (totalPrompts > 0 && completedPrompts > 0) {
|
|
44292
44458
|
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / completedPrompts;
|
|
44293
44459
|
const estimatedTotalDuration = moment__default["default"].duration(estimatedTotalMs);
|
|
44294
44460
|
const estimatedCompletion = startTime.clone().add(estimatedTotalDuration);
|
|
44295
|
-
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
44296
|
-
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
44461
|
+
estimatedTotalText = formatDurationBrief$1(estimatedTotalDuration);
|
|
44462
|
+
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS$1);
|
|
44297
44463
|
}
|
|
44298
44464
|
return {
|
|
44299
44465
|
totalPrompts,
|
|
@@ -44309,7 +44475,7 @@
|
|
|
44309
44475
|
/**
|
|
44310
44476
|
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
44311
44477
|
*/
|
|
44312
|
-
function formatDurationBrief(duration) {
|
|
44478
|
+
function formatDurationBrief$1(duration) {
|
|
44313
44479
|
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
44314
44480
|
const hours = Math.floor(totalSeconds / 3600);
|
|
44315
44481
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
@@ -44330,21 +44496,6 @@
|
|
|
44330
44496
|
return parts.join(' ');
|
|
44331
44497
|
}
|
|
44332
44498
|
|
|
44333
|
-
/**
|
|
44334
|
-
* Appends optional coding context to a runner prompt.
|
|
44335
|
-
*/
|
|
44336
|
-
function appendCoderContext(prompt, context) {
|
|
44337
|
-
const normalizedContext = context === null || context === void 0 ? void 0 : context.trim();
|
|
44338
|
-
if (!normalizedContext) {
|
|
44339
|
-
return prompt;
|
|
44340
|
-
}
|
|
44341
|
-
const normalizedPrompt = prompt.trimEnd();
|
|
44342
|
-
if (normalizedPrompt === '') {
|
|
44343
|
-
return normalizedContext;
|
|
44344
|
-
}
|
|
44345
|
-
return `${normalizedPrompt}\n\n${normalizedContext}`;
|
|
44346
|
-
}
|
|
44347
|
-
|
|
44348
44499
|
/**
|
|
44349
44500
|
* Git commands used to list changed and untracked files in the working tree.
|
|
44350
44501
|
*/
|
|
@@ -44614,7 +44765,7 @@
|
|
|
44614
44765
|
}
|
|
44615
44766
|
|
|
44616
44767
|
/**
|
|
44617
|
-
*
|
|
44768
|
+
* Current pause state.
|
|
44618
44769
|
*/
|
|
44619
44770
|
let pauseState = 'RUNNING';
|
|
44620
44771
|
/**
|
|
@@ -44651,17 +44802,48 @@
|
|
|
44651
44802
|
}
|
|
44652
44803
|
/**
|
|
44653
44804
|
* If the execution is paused, it will wait until it is resumed.
|
|
44805
|
+
*
|
|
44806
|
+
* @param options.silent - When `true`, suppresses console output (used when the terminal UI handles display).
|
|
44807
|
+
* @param options.onPaused - Callback invoked when entering the PAUSED state.
|
|
44808
|
+
* @param options.onResumed - Callback invoked when leaving the PAUSED state.
|
|
44654
44809
|
*/
|
|
44655
|
-
async function checkPause() {
|
|
44810
|
+
async function checkPause(options) {
|
|
44811
|
+
var _a, _b;
|
|
44656
44812
|
if (pauseState === 'PAUSING') {
|
|
44657
44813
|
pauseState = 'PAUSED';
|
|
44658
|
-
|
|
44814
|
+
if (!(options === null || options === void 0 ? void 0 : options.silent)) {
|
|
44815
|
+
console.log(colors__default["default"].bgWhite.black('Paused') + colors__default["default"].gray(' (Press "p" to resume)'));
|
|
44816
|
+
}
|
|
44817
|
+
(_a = options === null || options === void 0 ? void 0 : options.onPaused) === null || _a === void 0 ? void 0 : _a.call(options);
|
|
44659
44818
|
while (pauseState === 'PAUSED') {
|
|
44660
44819
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
44661
44820
|
}
|
|
44662
|
-
|
|
44821
|
+
(_b = options === null || options === void 0 ? void 0 : options.onResumed) === null || _b === void 0 ? void 0 : _b.call(options);
|
|
44822
|
+
if (!(options === null || options === void 0 ? void 0 : options.silent)) {
|
|
44823
|
+
console.log(colors__default["default"].green('Resuming...'));
|
|
44824
|
+
}
|
|
44663
44825
|
}
|
|
44664
44826
|
}
|
|
44827
|
+
/**
|
|
44828
|
+
* Returns the current pause state for external consumers such as the terminal UI.
|
|
44829
|
+
*/
|
|
44830
|
+
function getPauseState() {
|
|
44831
|
+
return pauseState;
|
|
44832
|
+
}
|
|
44833
|
+
/**
|
|
44834
|
+
* Requests a pause from an external controller (e.g. the Ink UI).
|
|
44835
|
+
*/
|
|
44836
|
+
function requestPause() {
|
|
44837
|
+
if (pauseState === 'RUNNING') {
|
|
44838
|
+
pauseState = 'PAUSING';
|
|
44839
|
+
}
|
|
44840
|
+
}
|
|
44841
|
+
/**
|
|
44842
|
+
* Resumes execution from an external controller after a pause.
|
|
44843
|
+
*/
|
|
44844
|
+
function requestResume() {
|
|
44845
|
+
pauseState = 'RUNNING';
|
|
44846
|
+
}
|
|
44665
44847
|
|
|
44666
44848
|
/**
|
|
44667
44849
|
* Environment variable that configures the name used for agent commits.
|
|
@@ -45006,7 +45188,7 @@
|
|
|
45006
45188
|
|
|
45007
45189
|
/**
|
|
45008
45190
|
* Commits staged changes with the provided message using the dedicated coding-agent identity when configured,
|
|
45009
|
-
* otherwise falls back to the default Git configuration.
|
|
45191
|
+
* otherwise falls back to the default Git configuration. Remote pushing is opt-in via `options.autoPush`.
|
|
45010
45192
|
*/
|
|
45011
45193
|
async function commitChanges(message, options) {
|
|
45012
45194
|
const projectPath = process.cwd();
|
|
@@ -45026,7 +45208,7 @@
|
|
|
45026
45208
|
cwd: projectPath,
|
|
45027
45209
|
env: agentEnv,
|
|
45028
45210
|
});
|
|
45029
|
-
if (
|
|
45211
|
+
if (options === null || options === void 0 ? void 0 : options.autoPush) {
|
|
45030
45212
|
await pushCommittedChanges(projectPath, agentEnv);
|
|
45031
45213
|
}
|
|
45032
45214
|
}
|
|
@@ -45392,6 +45574,7 @@
|
|
|
45392
45574
|
return value.split('\\').join('/');
|
|
45393
45575
|
}
|
|
45394
45576
|
|
|
45577
|
+
// cspell:ignore hashtext
|
|
45395
45578
|
/**
|
|
45396
45579
|
* Cross-process advisory lock key guarding migration execution.
|
|
45397
45580
|
*
|
|
@@ -45403,13 +45586,27 @@
|
|
|
45403
45586
|
*
|
|
45404
45587
|
* @param client Connected PostgreSQL client.
|
|
45405
45588
|
* @param logger Logger used for progress output.
|
|
45589
|
+
* @param mode Whether the caller should block for the lock or skip when it is already held.
|
|
45590
|
+
* @returns `true` when the lock was acquired and migrations may proceed.
|
|
45406
45591
|
*
|
|
45407
45592
|
* @private function of runDatabaseMigrations
|
|
45408
45593
|
*/
|
|
45409
|
-
async function acquireMigrationExecutionLock(client, logger) {
|
|
45594
|
+
async function acquireMigrationExecutionLock(client, logger, mode = 'wait') {
|
|
45595
|
+
var _a;
|
|
45596
|
+
if (mode === 'skip') {
|
|
45597
|
+
logger.info('🔒 Checking migration lock without waiting');
|
|
45598
|
+
const { rows } = await client.query('SELECT pg_try_advisory_lock(hashtext($1)) AS "isMigrationLockAcquired";', [DATABASE_MIGRATION_LOCK_KEY]);
|
|
45599
|
+
if (!((_a = rows[0]) === null || _a === void 0 ? void 0 : _a.isMigrationLockAcquired)) {
|
|
45600
|
+
logger.info('⏭️ Migration lock is already held by another process. Skipping this migration attempt.');
|
|
45601
|
+
return false;
|
|
45602
|
+
}
|
|
45603
|
+
logger.info('🔒 Migration lock acquired');
|
|
45604
|
+
return true;
|
|
45605
|
+
}
|
|
45410
45606
|
logger.info('🔒 Waiting for migration lock');
|
|
45411
45607
|
await client.query('SELECT pg_advisory_lock(hashtext($1));', [DATABASE_MIGRATION_LOCK_KEY]);
|
|
45412
45608
|
logger.info('🔒 Migration lock acquired');
|
|
45609
|
+
return true;
|
|
45413
45610
|
}
|
|
45414
45611
|
/**
|
|
45415
45612
|
* Releases advisory lock used for migration execution.
|
|
@@ -45933,23 +46130,33 @@
|
|
|
45933
46130
|
* @returns Aggregated migration summary.
|
|
45934
46131
|
*/
|
|
45935
46132
|
async function runDatabaseMigrations(options) {
|
|
45936
|
-
var _a, _b, _c, _d;
|
|
46133
|
+
var _a, _b, _c, _d, _e;
|
|
45937
46134
|
const logger = (_a = options.logger) !== null && _a !== void 0 ? _a : console;
|
|
45938
46135
|
const selectedPrefixes = selectPrefixesForMigration(options.prefixes, (_b = options.registeredServers) !== null && _b !== void 0 ? _b : [], options.onlyTargets);
|
|
45939
46136
|
const migrationsDirectory = (_c = options.migrationsDirectory) !== null && _c !== void 0 ? _c : (await resolveMigrationsDirectory());
|
|
45940
46137
|
const migrationFiles = await readMigrationFiles(migrationsDirectory);
|
|
46138
|
+
const totalMigrationFiles = migrationFiles.length;
|
|
45941
46139
|
const perPrefix = [];
|
|
45942
|
-
logger.info(`📂 Found ${
|
|
46140
|
+
logger.info(`📂 Found ${totalMigrationFiles} migration files`);
|
|
45943
46141
|
logger.info(`📋 Found ${selectedPrefixes.length} prefixes to migrate: ${selectedPrefixes
|
|
45944
46142
|
.map((prefix) => prefix || '<default>')
|
|
45945
46143
|
.join(', ')}`);
|
|
45946
46144
|
const client = await createPostgresClient(options.connectionString);
|
|
45947
46145
|
let hasExecutionLock = false;
|
|
46146
|
+
let isSkippedDueToActiveMigrationLock = false;
|
|
45948
46147
|
try {
|
|
45949
46148
|
await client.connect();
|
|
45950
46149
|
logger.info('🔌 Connected to database');
|
|
45951
|
-
await acquireMigrationExecutionLock(client, logger);
|
|
45952
|
-
hasExecutionLock
|
|
46150
|
+
hasExecutionLock = await acquireMigrationExecutionLock(client, logger, (_d = options.executionLockMode) !== null && _d !== void 0 ? _d : 'wait');
|
|
46151
|
+
if (!hasExecutionLock) {
|
|
46152
|
+
isSkippedDueToActiveMigrationLock = true;
|
|
46153
|
+
return {
|
|
46154
|
+
processedPrefixes: [],
|
|
46155
|
+
totalMigrationFiles,
|
|
46156
|
+
perPrefix,
|
|
46157
|
+
isSkippedDueToActiveMigrationLock,
|
|
46158
|
+
};
|
|
46159
|
+
}
|
|
45953
46160
|
for (const prefix of selectedPrefixes) {
|
|
45954
46161
|
logger.info(`\n🏗️ Migrating prefix: "${prefix}"`);
|
|
45955
46162
|
const appliedCount = await migratePrefix({
|
|
@@ -45960,7 +46167,7 @@
|
|
|
45960
46167
|
logger,
|
|
45961
46168
|
migrationFiles,
|
|
45962
46169
|
migrationsDirectory,
|
|
45963
|
-
logSqlStatements: (
|
|
46170
|
+
logSqlStatements: (_e = options.logSqlStatements) !== null && _e !== void 0 ? _e : false,
|
|
45964
46171
|
});
|
|
45965
46172
|
perPrefix.push({ prefix, appliedCount });
|
|
45966
46173
|
}
|
|
@@ -45973,8 +46180,9 @@
|
|
|
45973
46180
|
}
|
|
45974
46181
|
return {
|
|
45975
46182
|
processedPrefixes: selectedPrefixes,
|
|
45976
|
-
totalMigrationFiles
|
|
46183
|
+
totalMigrationFiles,
|
|
45977
46184
|
perPrefix,
|
|
46185
|
+
isSkippedDueToActiveMigrationLock,
|
|
45978
46186
|
};
|
|
45979
46187
|
}
|
|
45980
46188
|
/**
|
|
@@ -46593,6 +46801,19 @@
|
|
|
46593
46801
|
return `${prefix}$${price.toFixed(2)}`;
|
|
46594
46802
|
}
|
|
46595
46803
|
|
|
46804
|
+
/**
|
|
46805
|
+
* Formats optional attempt metadata stored in prompt status lines.
|
|
46806
|
+
*/
|
|
46807
|
+
function formatPromptAttemptMetadata(status, attemptCount) {
|
|
46808
|
+
if (attemptCount <= 1) {
|
|
46809
|
+
return '';
|
|
46810
|
+
}
|
|
46811
|
+
if (status === 'done') {
|
|
46812
|
+
return `(${attemptCount} attempts) `;
|
|
46813
|
+
}
|
|
46814
|
+
return `(failed after ${attemptCount} attempts) `;
|
|
46815
|
+
}
|
|
46816
|
+
|
|
46596
46817
|
/**
|
|
46597
46818
|
* Formats runner details for prompt status lines.
|
|
46598
46819
|
*/
|
|
@@ -46612,7 +46833,7 @@
|
|
|
46612
46833
|
/**
|
|
46613
46834
|
* Marks a prompt section as done and records usage pricing and runner details.
|
|
46614
46835
|
*/
|
|
46615
|
-
function markPromptDone(file, section, usage, runnerName, modelName, promptExecutionStartedDate) {
|
|
46836
|
+
function markPromptDone(file, section, usage, runnerName, modelName, promptExecutionStartedDate, attemptCount = 1) {
|
|
46616
46837
|
if (section.statusLineIndex === undefined) {
|
|
46617
46838
|
throw new Error(`Prompt ${section.index + 1} in ${file.name} does not have a status line.`);
|
|
46618
46839
|
}
|
|
@@ -46622,16 +46843,17 @@
|
|
|
46622
46843
|
}
|
|
46623
46844
|
const priceString = formatUsagePrice(usage);
|
|
46624
46845
|
const runnerSignature = formatRunnerSignature(runnerName, modelName);
|
|
46846
|
+
const attemptMetadata = formatPromptAttemptMetadata('done', attemptCount);
|
|
46625
46847
|
const duration = moment__default["default"]().diff(promptExecutionStartedDate);
|
|
46626
46848
|
const durationString = moment__default["default"].duration(duration).humanize();
|
|
46627
46849
|
// Replace "[ ]" or "[ ] !!..." with "[x] $price duration by runner"
|
|
46628
|
-
file.lines[section.statusLineIndex] = line.replace(/\[\s*\]\s*!*\s*$/, `[x] ${priceString} ${durationString} by ${runnerSignature}`);
|
|
46850
|
+
file.lines[section.statusLineIndex] = line.replace(/\[\s*\]\s*!*\s*$/, `[x] ${attemptMetadata}${priceString} ${durationString} by ${runnerSignature}`);
|
|
46629
46851
|
}
|
|
46630
46852
|
|
|
46631
46853
|
/**
|
|
46632
46854
|
* Marks a prompt section as failed and records runner details.
|
|
46633
46855
|
*/
|
|
46634
|
-
function markPromptFailed(file, section, runnerName, modelName, promptExecutionStartedDate) {
|
|
46856
|
+
function markPromptFailed(file, section, runnerName, modelName, promptExecutionStartedDate, attemptCount = 1) {
|
|
46635
46857
|
if (section.statusLineIndex === undefined) {
|
|
46636
46858
|
throw new Error(`Prompt ${section.index + 1} in ${file.name} does not have a status line.`);
|
|
46637
46859
|
}
|
|
@@ -46640,9 +46862,11 @@
|
|
|
46640
46862
|
throw new Error(`Prompt ${section.index + 1} in ${file.name} points to a missing status line.`);
|
|
46641
46863
|
}
|
|
46642
46864
|
const runnerSignature = formatRunnerSignature(runnerName, modelName);
|
|
46865
|
+
const attemptMetadata = formatPromptAttemptMetadata('failed', attemptCount);
|
|
46643
46866
|
const duration = moment__default["default"]().diff(promptExecutionStartedDate);
|
|
46644
46867
|
const durationString = moment__default["default"].duration(duration).humanize();
|
|
46645
|
-
|
|
46868
|
+
const failureDetails = attemptMetadata === '' ? `failed after ${durationString} by ${runnerSignature}` : `${attemptMetadata}${durationString} by ${runnerSignature}`;
|
|
46869
|
+
file.lines[section.statusLineIndex] = line.replace(/\[\s*\]\s*!*\s*$/, `[!] ${failureDetails}`);
|
|
46646
46870
|
}
|
|
46647
46871
|
|
|
46648
46872
|
/**
|
|
@@ -46759,6 +46983,20 @@
|
|
|
46759
46983
|
await waitForEnter(colors__default["default"].bgWhite(`Press Enter to start the ${label}...`));
|
|
46760
46984
|
}
|
|
46761
46985
|
|
|
46986
|
+
/**
|
|
46987
|
+
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
46988
|
+
*/
|
|
46989
|
+
function formatUnknownErrorDetails(error) {
|
|
46990
|
+
if (error instanceof Error) {
|
|
46991
|
+
return error.stack || error.message;
|
|
46992
|
+
}
|
|
46993
|
+
if (typeof error === 'string') {
|
|
46994
|
+
return error;
|
|
46995
|
+
}
|
|
46996
|
+
const serializedError = JSON.stringify(error, null, 2);
|
|
46997
|
+
return serializedError !== null && serializedError !== void 0 ? serializedError : String(error);
|
|
46998
|
+
}
|
|
46999
|
+
|
|
46762
47000
|
/**
|
|
46763
47001
|
* Writes the failure details for a single prompt run next to the prompt markdown file.
|
|
46764
47002
|
*/
|
|
@@ -46766,7 +47004,7 @@
|
|
|
46766
47004
|
const logPath = buildPromptErrorLogPath(options.file.path);
|
|
46767
47005
|
const label = buildPromptLabelForDisplay(options.file, options.section);
|
|
46768
47006
|
const summary = buildPromptSummary(options.file, options.section);
|
|
46769
|
-
const details =
|
|
47007
|
+
const details = formatUnknownErrorDetails(options.error);
|
|
46770
47008
|
const modelSuffix = options.modelName ? ` (${options.modelName})` : '';
|
|
46771
47009
|
const runnerLabel = `${options.runnerName || 'unknown'}${modelSuffix}`;
|
|
46772
47010
|
const log = [
|
|
@@ -46793,18 +47031,6 @@
|
|
|
46793
47031
|
}
|
|
46794
47032
|
return `${promptPath}.error.log`;
|
|
46795
47033
|
}
|
|
46796
|
-
/**
|
|
46797
|
-
* Formats unknown error values into a readable log payload.
|
|
46798
|
-
*/
|
|
46799
|
-
function buildErrorDetails(error) {
|
|
46800
|
-
if (error instanceof Error) {
|
|
46801
|
-
return error.stack || error.message;
|
|
46802
|
-
}
|
|
46803
|
-
if (typeof error === 'string') {
|
|
46804
|
-
return error;
|
|
46805
|
-
}
|
|
46806
|
-
return JSON.stringify(error, null, 2);
|
|
46807
|
-
}
|
|
46808
47034
|
|
|
46809
47035
|
/**
|
|
46810
47036
|
* Writes updated prompt file content to disk.
|
|
@@ -47863,6 +48089,647 @@
|
|
|
47863
48089
|
}
|
|
47864
48090
|
}
|
|
47865
48091
|
|
|
48092
|
+
/**
|
|
48093
|
+
* Runs the configured verification command inside the project root and returns its output.
|
|
48094
|
+
*/
|
|
48095
|
+
async function runPromptTestCommand(options) {
|
|
48096
|
+
const projectPath = toPosixPath(options.projectPath);
|
|
48097
|
+
return await $runGoScriptWithOutput({
|
|
48098
|
+
scriptPath: options.scriptPath,
|
|
48099
|
+
scriptContent: spaceTrim(`
|
|
48100
|
+
cd "${projectPath}"
|
|
48101
|
+
${options.command}
|
|
48102
|
+
`),
|
|
48103
|
+
});
|
|
48104
|
+
}
|
|
48105
|
+
|
|
48106
|
+
/**
|
|
48107
|
+
* Maximum number of coding attempts allowed for the same prompt when verification keeps failing.
|
|
48108
|
+
*/
|
|
48109
|
+
const MAX_PROMPT_TEST_ATTEMPTS = 3;
|
|
48110
|
+
/**
|
|
48111
|
+
* Maximum amount of verification output sent back to the coding agent as retry feedback.
|
|
48112
|
+
*/
|
|
48113
|
+
const MAX_TEST_FEEDBACK_OUTPUT_CHARS = 12000;
|
|
48114
|
+
/**
|
|
48115
|
+
* Runs one coding prompt and, when configured, verifies it with a shell command that can feed failures back.
|
|
48116
|
+
*/
|
|
48117
|
+
async function runPromptWithTestFeedback(options) {
|
|
48118
|
+
var _a, _b, _c, _d;
|
|
48119
|
+
const normalizedTestCommand = (_a = options.testCommand) === null || _a === void 0 ? void 0 : _a.trim();
|
|
48120
|
+
if (!normalizedTestCommand) {
|
|
48121
|
+
(_b = options.onAttemptStarted) === null || _b === void 0 ? void 0 : _b.call(options, 1);
|
|
48122
|
+
const result = await options.runner.runPrompt({
|
|
48123
|
+
prompt: options.prompt,
|
|
48124
|
+
scriptPath: options.scriptPath,
|
|
48125
|
+
projectPath: options.projectPath,
|
|
48126
|
+
});
|
|
48127
|
+
return { ...result, attemptCount: 1 };
|
|
48128
|
+
}
|
|
48129
|
+
const runPromptTestCommandExecutor = (_c = options.runPromptTestCommandExecutor) !== null && _c !== void 0 ? _c : runPromptTestCommand;
|
|
48130
|
+
let promptForCurrentAttempt = options.prompt;
|
|
48131
|
+
for (let attemptCount = 1; attemptCount <= MAX_PROMPT_TEST_ATTEMPTS; attemptCount++) {
|
|
48132
|
+
(_d = options.onAttemptStarted) === null || _d === void 0 ? void 0 : _d.call(options, attemptCount);
|
|
48133
|
+
const result = await options.runner.runPrompt({
|
|
48134
|
+
prompt: promptForCurrentAttempt,
|
|
48135
|
+
scriptPath: options.scriptPath,
|
|
48136
|
+
projectPath: options.projectPath,
|
|
48137
|
+
});
|
|
48138
|
+
console.info(colors__default["default"].gray(`Running verification command after attempt #${attemptCount}: ${normalizedTestCommand}`));
|
|
48139
|
+
try {
|
|
48140
|
+
await runPromptTestCommandExecutor({
|
|
48141
|
+
command: normalizedTestCommand,
|
|
48142
|
+
projectPath: options.projectPath,
|
|
48143
|
+
scriptPath: buildPromptTestScriptPath(options.scriptPath),
|
|
48144
|
+
});
|
|
48145
|
+
return { ...result, attemptCount };
|
|
48146
|
+
}
|
|
48147
|
+
catch (error) {
|
|
48148
|
+
const fullVerificationOutput = formatUnknownErrorDetails(error);
|
|
48149
|
+
const feedbackVerificationOutput = limitVerificationOutputForFeedback(fullVerificationOutput);
|
|
48150
|
+
if (attemptCount >= MAX_PROMPT_TEST_ATTEMPTS) {
|
|
48151
|
+
console.error(colors__default["default"].red(`Verification failed for ${options.promptLabel} after ${attemptCount} attempts.`));
|
|
48152
|
+
throw new Error(buildFinalVerificationFailureMessage({
|
|
48153
|
+
promptLabel: options.promptLabel,
|
|
48154
|
+
testCommand: normalizedTestCommand,
|
|
48155
|
+
attemptCount,
|
|
48156
|
+
verificationOutput: fullVerificationOutput,
|
|
48157
|
+
}));
|
|
48158
|
+
}
|
|
48159
|
+
console.warn(colors__default["default"].yellow(`Verification failed for ${options.promptLabel} on attempt #${attemptCount}. Sending feedback to ${options.runner.name} and retrying...`));
|
|
48160
|
+
promptForCurrentAttempt = appendCoderContext(options.prompt, buildVerificationFeedback({
|
|
48161
|
+
testCommand: normalizedTestCommand,
|
|
48162
|
+
failedAttemptCount: attemptCount,
|
|
48163
|
+
verificationOutput: feedbackVerificationOutput,
|
|
48164
|
+
}));
|
|
48165
|
+
}
|
|
48166
|
+
}
|
|
48167
|
+
throw new Error('Unexpected prompt verification state.');
|
|
48168
|
+
}
|
|
48169
|
+
/**
|
|
48170
|
+
* Builds one feedback block appended to the next coding attempt after tests fail.
|
|
48171
|
+
*/
|
|
48172
|
+
function buildVerificationFeedback({ testCommand, failedAttemptCount, verificationOutput, }) {
|
|
48173
|
+
const nextAttemptCount = failedAttemptCount + 1;
|
|
48174
|
+
return spaceTrim((block) => `
|
|
48175
|
+
The previous implementation did not pass the required verification command.
|
|
48176
|
+
|
|
48177
|
+
## Automated verification feedback
|
|
48178
|
+
- Retry attempt: ${nextAttemptCount} of ${MAX_PROMPT_TEST_ATTEMPTS}
|
|
48179
|
+
- Verification command: \`${testCommand}\`
|
|
48180
|
+
- Update the current implementation so the verification command passes without breaking the original task requirements.
|
|
48181
|
+
|
|
48182
|
+
### Verification output
|
|
48183
|
+
\`\`\`
|
|
48184
|
+
${block(verificationOutput)}
|
|
48185
|
+
\`\`\`
|
|
48186
|
+
`);
|
|
48187
|
+
}
|
|
48188
|
+
/**
|
|
48189
|
+
* Builds the final error message written when verification still fails after all retries.
|
|
48190
|
+
*/
|
|
48191
|
+
function buildFinalVerificationFailureMessage({ promptLabel, testCommand, attemptCount, verificationOutput, }) {
|
|
48192
|
+
return spaceTrim((block) => `
|
|
48193
|
+
Verification command \`${testCommand}\` failed for \`${promptLabel}\` after ${attemptCount} attempts.
|
|
48194
|
+
|
|
48195
|
+
### Verification output
|
|
48196
|
+
\`\`\`
|
|
48197
|
+
${block(verificationOutput)}
|
|
48198
|
+
\`\`\`
|
|
48199
|
+
`);
|
|
48200
|
+
}
|
|
48201
|
+
/**
|
|
48202
|
+
* Limits verification output before it is embedded back into the next coding prompt.
|
|
48203
|
+
*/
|
|
48204
|
+
function limitVerificationOutputForFeedback(verificationOutput) {
|
|
48205
|
+
const normalizedVerificationOutput = verificationOutput.trim();
|
|
48206
|
+
if (normalizedVerificationOutput.length <= MAX_TEST_FEEDBACK_OUTPUT_CHARS) {
|
|
48207
|
+
return normalizedVerificationOutput;
|
|
48208
|
+
}
|
|
48209
|
+
return spaceTrim(`
|
|
48210
|
+
[...verification output truncated to the last ${MAX_TEST_FEEDBACK_OUTPUT_CHARS} characters...]
|
|
48211
|
+
${normalizedVerificationOutput.slice(-MAX_TEST_FEEDBACK_OUTPUT_CHARS)}
|
|
48212
|
+
`);
|
|
48213
|
+
}
|
|
48214
|
+
/**
|
|
48215
|
+
* Derives a dedicated temp-script path for verification commands.
|
|
48216
|
+
*/
|
|
48217
|
+
function buildPromptTestScriptPath(scriptPath) {
|
|
48218
|
+
if (scriptPath.toLowerCase().endsWith('.sh')) {
|
|
48219
|
+
return `${scriptPath.slice(0, -3)}.test.sh`;
|
|
48220
|
+
}
|
|
48221
|
+
return `${scriptPath}.test.sh`;
|
|
48222
|
+
}
|
|
48223
|
+
|
|
48224
|
+
/**
|
|
48225
|
+
* Maximum number of agent output lines kept in the scrolling output area.
|
|
48226
|
+
*
|
|
48227
|
+
* @private internal constant of coder run UI
|
|
48228
|
+
*/
|
|
48229
|
+
const MAX_AGENT_OUTPUT_LINES = 12;
|
|
48230
|
+
/**
|
|
48231
|
+
* Calendar formats used when displaying the estimated completion time.
|
|
48232
|
+
*
|
|
48233
|
+
* @private internal constant of coder run UI
|
|
48234
|
+
*/
|
|
48235
|
+
const ESTIMATED_DONE_CALENDAR_FORMATS = {
|
|
48236
|
+
sameDay: '[Today] h:mm',
|
|
48237
|
+
nextDay: '[Tomorrow] h:mm',
|
|
48238
|
+
nextWeek: 'dddd h:mm',
|
|
48239
|
+
lastDay: '[Yesterday] h:mm',
|
|
48240
|
+
lastWeek: 'dddd h:mm',
|
|
48241
|
+
sameElse: 'MMM D h:mm',
|
|
48242
|
+
};
|
|
48243
|
+
/**
|
|
48244
|
+
* Reactive state manager for the coder run terminal UI.
|
|
48245
|
+
*
|
|
48246
|
+
* Holds all data the Ink components need and emits `'change'` events
|
|
48247
|
+
* whenever any property is updated so the UI can re-render.
|
|
48248
|
+
*
|
|
48249
|
+
* @private internal utility of coder run UI
|
|
48250
|
+
*/
|
|
48251
|
+
class CoderRunUiState extends events.EventEmitter {
|
|
48252
|
+
constructor(startTime) {
|
|
48253
|
+
super();
|
|
48254
|
+
this.config = { agentName: '', priority: 0 };
|
|
48255
|
+
this.currentPromptLabel = '';
|
|
48256
|
+
this.currentAttempt = 1;
|
|
48257
|
+
this.maxAttempts = 3;
|
|
48258
|
+
this.agentOutputLines = [];
|
|
48259
|
+
this.phase = 'initializing';
|
|
48260
|
+
this.statusMessage = 'Initializing...';
|
|
48261
|
+
this.errors = [];
|
|
48262
|
+
this.stats = { done: 0, forAgent: 0, belowMinimumPriority: 0, toBeWritten: 0 };
|
|
48263
|
+
/**
|
|
48264
|
+
* Total milliseconds the timer was paused/waiting (excluded from elapsed display).
|
|
48265
|
+
*/
|
|
48266
|
+
this.pausedMs = 0;
|
|
48267
|
+
this.startTime = startTime;
|
|
48268
|
+
// Timer starts paused — callers call `resumeTimer()` when actual work begins.
|
|
48269
|
+
this.pausedSince = startTime.clone();
|
|
48270
|
+
}
|
|
48271
|
+
/**
|
|
48272
|
+
* Pauses the elapsed timer (e.g. while waiting for user input or paused state).
|
|
48273
|
+
*/
|
|
48274
|
+
pauseTimer() {
|
|
48275
|
+
if (this.pausedSince === undefined) {
|
|
48276
|
+
this.pausedSince = moment__default["default"]();
|
|
48277
|
+
}
|
|
48278
|
+
}
|
|
48279
|
+
/**
|
|
48280
|
+
* Resumes the elapsed timer after a pause.
|
|
48281
|
+
*/
|
|
48282
|
+
resumeTimer() {
|
|
48283
|
+
if (this.pausedSince !== undefined) {
|
|
48284
|
+
this.pausedMs += moment__default["default"]().diff(this.pausedSince);
|
|
48285
|
+
this.pausedSince = undefined;
|
|
48286
|
+
}
|
|
48287
|
+
}
|
|
48288
|
+
/**
|
|
48289
|
+
* Replaces the configuration shown in the UI header.
|
|
48290
|
+
*/
|
|
48291
|
+
setConfig(config) {
|
|
48292
|
+
this.config = config;
|
|
48293
|
+
this.emitChange();
|
|
48294
|
+
}
|
|
48295
|
+
/**
|
|
48296
|
+
* Feeds new prompt statistics from the main loop so the progress bar updates.
|
|
48297
|
+
*/
|
|
48298
|
+
updateProgress(stats) {
|
|
48299
|
+
if (this.initialDone === undefined && (stats.done > 0 || stats.forAgent > 0 || stats.toBeWritten > 0)) {
|
|
48300
|
+
this.initialDone = stats.done;
|
|
48301
|
+
}
|
|
48302
|
+
this.stats = stats;
|
|
48303
|
+
this.emitChange();
|
|
48304
|
+
}
|
|
48305
|
+
/**
|
|
48306
|
+
* Computes a progress snapshot on demand so elapsed time ticks with periodic re-renders.
|
|
48307
|
+
*/
|
|
48308
|
+
getProgress() {
|
|
48309
|
+
var _a;
|
|
48310
|
+
const stats = this.stats;
|
|
48311
|
+
const totalPrompts = stats.done + stats.forAgent + stats.toBeWritten;
|
|
48312
|
+
const sessionDone = Math.max(0, stats.done - ((_a = this.initialDone) !== null && _a !== void 0 ? _a : stats.done));
|
|
48313
|
+
const sessionTotal = sessionDone + stats.forAgent;
|
|
48314
|
+
const percentage = totalPrompts > 0 ? Math.round((stats.done / totalPrompts) * 100) : 0;
|
|
48315
|
+
const wallMs = moment__default["default"]().diff(this.startTime);
|
|
48316
|
+
const currentPauseMs = this.pausedSince !== undefined ? moment__default["default"]().diff(this.pausedSince) : 0;
|
|
48317
|
+
const activeMs = Math.max(0, wallMs - this.pausedMs - currentPauseMs);
|
|
48318
|
+
const elapsedDuration = moment__default["default"].duration(activeMs);
|
|
48319
|
+
const elapsedText = formatDurationBrief(elapsedDuration);
|
|
48320
|
+
let estimatedTotalText = '\u2014';
|
|
48321
|
+
let estimatedLabel = 'unknown';
|
|
48322
|
+
if (totalPrompts > 0 && stats.done > 0) {
|
|
48323
|
+
const estimatedTotalMs = (elapsedDuration.asMilliseconds() * totalPrompts) / stats.done;
|
|
48324
|
+
const estimatedRemainingMs = estimatedTotalMs - elapsedDuration.asMilliseconds();
|
|
48325
|
+
const estimatedTotalDuration = moment__default["default"].duration(estimatedTotalMs);
|
|
48326
|
+
const estimatedCompletion = moment__default["default"]().add(estimatedRemainingMs, 'milliseconds');
|
|
48327
|
+
estimatedTotalText = formatDurationBrief(estimatedTotalDuration);
|
|
48328
|
+
estimatedLabel = estimatedCompletion.calendar(null, ESTIMATED_DONE_CALENDAR_FORMATS);
|
|
48329
|
+
}
|
|
48330
|
+
return {
|
|
48331
|
+
totalPrompts,
|
|
48332
|
+
sessionDone,
|
|
48333
|
+
sessionTotal,
|
|
48334
|
+
percentage,
|
|
48335
|
+
elapsedText,
|
|
48336
|
+
estimatedTotalText,
|
|
48337
|
+
estimatedLabel,
|
|
48338
|
+
};
|
|
48339
|
+
}
|
|
48340
|
+
/**
|
|
48341
|
+
* Sets the label of the prompt currently being processed and resets per-prompt state.
|
|
48342
|
+
*/
|
|
48343
|
+
setCurrentPrompt(label) {
|
|
48344
|
+
this.currentPromptLabel = label;
|
|
48345
|
+
this.agentOutputLines = [];
|
|
48346
|
+
this.currentAttempt = 1;
|
|
48347
|
+
this.emitChange();
|
|
48348
|
+
}
|
|
48349
|
+
/**
|
|
48350
|
+
* Updates the current retry attempt number.
|
|
48351
|
+
*/
|
|
48352
|
+
setAttempt(attempt) {
|
|
48353
|
+
this.currentAttempt = attempt;
|
|
48354
|
+
this.emitChange();
|
|
48355
|
+
}
|
|
48356
|
+
/**
|
|
48357
|
+
* Appends raw agent output text, keeping only the last `MAX_AGENT_OUTPUT_LINES`.
|
|
48358
|
+
*/
|
|
48359
|
+
addAgentOutput(text) {
|
|
48360
|
+
const lines = text.split(/\r?\n/).filter((line) => line.trim() !== '');
|
|
48361
|
+
if (lines.length === 0) {
|
|
48362
|
+
return;
|
|
48363
|
+
}
|
|
48364
|
+
this.agentOutputLines.push(...lines);
|
|
48365
|
+
if (this.agentOutputLines.length > MAX_AGENT_OUTPUT_LINES) {
|
|
48366
|
+
this.agentOutputLines = this.agentOutputLines.slice(-MAX_AGENT_OUTPUT_LINES);
|
|
48367
|
+
}
|
|
48368
|
+
this.emitChange();
|
|
48369
|
+
}
|
|
48370
|
+
/**
|
|
48371
|
+
* Transitions the execution phase shown in the UI.
|
|
48372
|
+
*/
|
|
48373
|
+
setPhase(phase) {
|
|
48374
|
+
this.phase = phase;
|
|
48375
|
+
this.emitChange();
|
|
48376
|
+
}
|
|
48377
|
+
/**
|
|
48378
|
+
* Updates the status message line beneath the current prompt label.
|
|
48379
|
+
*/
|
|
48380
|
+
setStatusMessage(message) {
|
|
48381
|
+
this.statusMessage = message;
|
|
48382
|
+
this.emitChange();
|
|
48383
|
+
}
|
|
48384
|
+
/**
|
|
48385
|
+
* Appends an error message to the error list shown in the UI.
|
|
48386
|
+
*/
|
|
48387
|
+
addError(errorMessage) {
|
|
48388
|
+
this.errors.push(errorMessage);
|
|
48389
|
+
this.emitChange();
|
|
48390
|
+
}
|
|
48391
|
+
emitChange() {
|
|
48392
|
+
this.emit('change');
|
|
48393
|
+
}
|
|
48394
|
+
}
|
|
48395
|
+
/**
|
|
48396
|
+
* Formats a duration into a compact string such as "3h 12m" or "45s".
|
|
48397
|
+
*
|
|
48398
|
+
* @private internal utility of coder run UI
|
|
48399
|
+
*/
|
|
48400
|
+
function formatDurationBrief(duration) {
|
|
48401
|
+
const totalSeconds = Math.max(0, Math.round(duration.asSeconds()));
|
|
48402
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
48403
|
+
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
48404
|
+
const seconds = totalSeconds % 60;
|
|
48405
|
+
const parts = [];
|
|
48406
|
+
if (hours > 0) {
|
|
48407
|
+
parts.push(`${hours}h`);
|
|
48408
|
+
}
|
|
48409
|
+
if (minutes > 0) {
|
|
48410
|
+
parts.push(`${minutes}m`);
|
|
48411
|
+
}
|
|
48412
|
+
if (!parts.length && seconds > 0) {
|
|
48413
|
+
parts.push(`${seconds}s`);
|
|
48414
|
+
}
|
|
48415
|
+
if (!parts.length) {
|
|
48416
|
+
parts.push('0s');
|
|
48417
|
+
}
|
|
48418
|
+
return parts.join(' ');
|
|
48419
|
+
}
|
|
48420
|
+
|
|
48421
|
+
/**
|
|
48422
|
+
* Refresh interval for the terminal UI in milliseconds.
|
|
48423
|
+
*
|
|
48424
|
+
* @private internal constant of coder run UI
|
|
48425
|
+
*/
|
|
48426
|
+
const UI_REFRESH_INTERVAL_MS = 200;
|
|
48427
|
+
/**
|
|
48428
|
+
* Character width used for the text progress bar.
|
|
48429
|
+
*
|
|
48430
|
+
* @private internal constant of coder run UI
|
|
48431
|
+
*/
|
|
48432
|
+
const PROGRESS_BAR_WIDTH = 40;
|
|
48433
|
+
/**
|
|
48434
|
+
* Maximum number of output lines reserved for agent output in the UI.
|
|
48435
|
+
*
|
|
48436
|
+
* @private internal constant of coder run UI
|
|
48437
|
+
*/
|
|
48438
|
+
const MAX_VISIBLE_OUTPUT_LINES = 8;
|
|
48439
|
+
/**
|
|
48440
|
+
* Spinner animation frames.
|
|
48441
|
+
*
|
|
48442
|
+
* @private internal constant of coder run UI
|
|
48443
|
+
*/
|
|
48444
|
+
const SPINNER_FRAMES = [
|
|
48445
|
+
'\u280B',
|
|
48446
|
+
'\u2819',
|
|
48447
|
+
'\u2839',
|
|
48448
|
+
'\u2838',
|
|
48449
|
+
'\u283C',
|
|
48450
|
+
'\u2834',
|
|
48451
|
+
'\u2826',
|
|
48452
|
+
'\u2827',
|
|
48453
|
+
'\u2807',
|
|
48454
|
+
'\u280F',
|
|
48455
|
+
];
|
|
48456
|
+
/**
|
|
48457
|
+
* Strips ANSI escape codes from a string.
|
|
48458
|
+
*
|
|
48459
|
+
* @private internal utility of coder run UI
|
|
48460
|
+
*/
|
|
48461
|
+
function stripAnsi(text) {
|
|
48462
|
+
// eslint-disable-next-line no-control-regex
|
|
48463
|
+
return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, '');
|
|
48464
|
+
}
|
|
48465
|
+
/**
|
|
48466
|
+
* Returns the usable terminal width, capped at 80.
|
|
48467
|
+
*
|
|
48468
|
+
* @private internal utility of coder run UI
|
|
48469
|
+
*/
|
|
48470
|
+
function getTerminalWidth() {
|
|
48471
|
+
return Math.min(process.stdout.columns || 80, 80);
|
|
48472
|
+
}
|
|
48473
|
+
/**
|
|
48474
|
+
* Builds a text progress bar string from a percentage.
|
|
48475
|
+
*
|
|
48476
|
+
* @private internal utility of coder run UI
|
|
48477
|
+
*/
|
|
48478
|
+
function buildProgressBar(percentage) {
|
|
48479
|
+
const filled = Math.round((percentage / 100) * PROGRESS_BAR_WIDTH);
|
|
48480
|
+
const empty = PROGRESS_BAR_WIDTH - filled;
|
|
48481
|
+
return colors__default["default"].green('\u2588'.repeat(filled)) + colors__default["default"].gray('\u2591'.repeat(empty)) + ` ${percentage}%`;
|
|
48482
|
+
}
|
|
48483
|
+
/**
|
|
48484
|
+
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
48485
|
+
*
|
|
48486
|
+
* The UI reserves a fixed number of terminal lines and repaints them periodically.
|
|
48487
|
+
* Between repaints, any console output from runners is captured and fed into the
|
|
48488
|
+
* scrolling agent-output area.
|
|
48489
|
+
*
|
|
48490
|
+
* On non-interactive (non-TTY) terminals the UI is skipped entirely and
|
|
48491
|
+
* only the state object is provided.
|
|
48492
|
+
*
|
|
48493
|
+
* @private internal entry point of coder run UI
|
|
48494
|
+
*/
|
|
48495
|
+
function renderCoderRunUi(startTime) {
|
|
48496
|
+
const state = new CoderRunUiState(startTime);
|
|
48497
|
+
if (!process.stdout.isTTY) {
|
|
48498
|
+
return {
|
|
48499
|
+
state,
|
|
48500
|
+
startCapturingAgentOutput: () => { },
|
|
48501
|
+
stopCapturingAgentOutput: () => { },
|
|
48502
|
+
cleanup: () => { },
|
|
48503
|
+
};
|
|
48504
|
+
}
|
|
48505
|
+
// --- Console interception ---
|
|
48506
|
+
const originalConsoleInfo = console.info;
|
|
48507
|
+
const originalConsoleWarn = console.warn;
|
|
48508
|
+
const originalConsoleError = console.error;
|
|
48509
|
+
const originalConsoleLog = console.log;
|
|
48510
|
+
let isCapturing = false;
|
|
48511
|
+
console.info = (...args) => {
|
|
48512
|
+
if (isCapturing) {
|
|
48513
|
+
state.addAgentOutput(args.map(String).join(' '));
|
|
48514
|
+
}
|
|
48515
|
+
// In UI mode, non-captured output is intentionally suppressed
|
|
48516
|
+
// so it does not interfere with the repainted frame.
|
|
48517
|
+
};
|
|
48518
|
+
console.warn = (...args) => {
|
|
48519
|
+
if (isCapturing) {
|
|
48520
|
+
state.addAgentOutput(args.map(String).join(' '));
|
|
48521
|
+
}
|
|
48522
|
+
};
|
|
48523
|
+
console.error = (...args) => {
|
|
48524
|
+
if (isCapturing) {
|
|
48525
|
+
state.addError(args.map(String).join(' '));
|
|
48526
|
+
}
|
|
48527
|
+
};
|
|
48528
|
+
console.log = (...args) => {
|
|
48529
|
+
if (isCapturing) {
|
|
48530
|
+
state.addAgentOutput(args.map(String).join(' '));
|
|
48531
|
+
}
|
|
48532
|
+
};
|
|
48533
|
+
// --- Keyboard input (pause) ---
|
|
48534
|
+
const readline$1 = require('readline');
|
|
48535
|
+
readline$1.emitKeypressEvents(process.stdin);
|
|
48536
|
+
if (process.stdin.isTTY) {
|
|
48537
|
+
process.stdin.setRawMode(true);
|
|
48538
|
+
}
|
|
48539
|
+
const keypressHandler = (_str, key) => {
|
|
48540
|
+
if (key.ctrl && key.name === 'c') {
|
|
48541
|
+
cleanup();
|
|
48542
|
+
process.exit(0);
|
|
48543
|
+
}
|
|
48544
|
+
if (key.name === 'p') {
|
|
48545
|
+
const current = getPauseState();
|
|
48546
|
+
if (current === 'RUNNING') {
|
|
48547
|
+
requestPause();
|
|
48548
|
+
}
|
|
48549
|
+
else {
|
|
48550
|
+
requestResume();
|
|
48551
|
+
}
|
|
48552
|
+
}
|
|
48553
|
+
};
|
|
48554
|
+
process.stdin.on('keypress', keypressHandler);
|
|
48555
|
+
// --- Rendering ---
|
|
48556
|
+
let spinnerFrame = 0;
|
|
48557
|
+
let previousFrameLineCount = 0;
|
|
48558
|
+
let isRendering = false;
|
|
48559
|
+
let renderScheduled = false;
|
|
48560
|
+
/**
|
|
48561
|
+
* Schedules a render on the next tick if one isn't already pending.
|
|
48562
|
+
* Prevents overlapping renders that cause cursor desync.
|
|
48563
|
+
*/
|
|
48564
|
+
function scheduleRender() {
|
|
48565
|
+
if (renderScheduled) {
|
|
48566
|
+
return;
|
|
48567
|
+
}
|
|
48568
|
+
renderScheduled = true;
|
|
48569
|
+
setImmediate(() => {
|
|
48570
|
+
renderScheduled = false;
|
|
48571
|
+
render();
|
|
48572
|
+
});
|
|
48573
|
+
}
|
|
48574
|
+
/**
|
|
48575
|
+
* Clears previously rendered lines and writes a new frame.
|
|
48576
|
+
*/
|
|
48577
|
+
function render() {
|
|
48578
|
+
if (isRendering) {
|
|
48579
|
+
return;
|
|
48580
|
+
}
|
|
48581
|
+
isRendering = true;
|
|
48582
|
+
try {
|
|
48583
|
+
const lines = buildFrame();
|
|
48584
|
+
// Move cursor up to clear the previous frame.
|
|
48585
|
+
if (previousFrameLineCount > 0) {
|
|
48586
|
+
process.stdout.write(`\x1b[${previousFrameLineCount}A`);
|
|
48587
|
+
}
|
|
48588
|
+
for (let i = 0; i < lines.length; i++) {
|
|
48589
|
+
readline.clearLine(process.stdout, 0);
|
|
48590
|
+
readline.cursorTo(process.stdout, 0);
|
|
48591
|
+
process.stdout.write(lines[i]);
|
|
48592
|
+
if (i < lines.length - 1) {
|
|
48593
|
+
process.stdout.write('\n');
|
|
48594
|
+
}
|
|
48595
|
+
}
|
|
48596
|
+
// Clear any leftover lines from a previous longer frame.
|
|
48597
|
+
if (lines.length < previousFrameLineCount) {
|
|
48598
|
+
for (let i = lines.length; i < previousFrameLineCount; i++) {
|
|
48599
|
+
process.stdout.write('\n');
|
|
48600
|
+
readline.clearLine(process.stdout, 0);
|
|
48601
|
+
readline.cursorTo(process.stdout, 0);
|
|
48602
|
+
}
|
|
48603
|
+
// Move back up to the end of the current frame.
|
|
48604
|
+
const overshoot = previousFrameLineCount - lines.length;
|
|
48605
|
+
if (overshoot > 0) {
|
|
48606
|
+
process.stdout.write(`\x1b[${overshoot}A`);
|
|
48607
|
+
}
|
|
48608
|
+
}
|
|
48609
|
+
previousFrameLineCount = lines.length;
|
|
48610
|
+
spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
|
|
48611
|
+
}
|
|
48612
|
+
finally {
|
|
48613
|
+
isRendering = false;
|
|
48614
|
+
}
|
|
48615
|
+
}
|
|
48616
|
+
/**
|
|
48617
|
+
* Builds the complete frame as an array of terminal lines.
|
|
48618
|
+
*/
|
|
48619
|
+
function buildFrame() {
|
|
48620
|
+
const w = getTerminalWidth();
|
|
48621
|
+
const sep = colors__default["default"].gray('\u2500'.repeat(w - 2));
|
|
48622
|
+
const spinner = SPINNER_FRAMES[spinnerFrame];
|
|
48623
|
+
const { config, phase, currentPromptLabel, currentAttempt, maxAttempts, statusMessage, agentOutputLines, errors, } = state;
|
|
48624
|
+
const progress = state.getProgress();
|
|
48625
|
+
const isPaused = getPauseState() !== 'RUNNING';
|
|
48626
|
+
const isActive = phase === 'running' || phase === 'verifying' || phase === 'loading';
|
|
48627
|
+
const lines = [];
|
|
48628
|
+
// --- Branding ---
|
|
48629
|
+
lines.push(colors__default["default"].bold.cyan('\u2728 Promptbook Coder'));
|
|
48630
|
+
// --- Config ---
|
|
48631
|
+
let configLine1 = `Agent: ${colors__default["default"].bold.green(config.agentName)}`;
|
|
48632
|
+
if (config.modelName) {
|
|
48633
|
+
configLine1 += ` \u2502 Model: ${colors__default["default"].bold(config.modelName)}`;
|
|
48634
|
+
}
|
|
48635
|
+
if (config.thinkingLevel) {
|
|
48636
|
+
configLine1 += ` \u2502 Thinking: ${colors__default["default"].bold(config.thinkingLevel)}`;
|
|
48637
|
+
}
|
|
48638
|
+
lines.push(configLine1);
|
|
48639
|
+
let configLine2 = '';
|
|
48640
|
+
if (config.context) {
|
|
48641
|
+
configLine2 += `Context: ${colors__default["default"].yellow(config.context)} \u2502 `;
|
|
48642
|
+
}
|
|
48643
|
+
configLine2 += `Priority: \u2265${config.priority}`;
|
|
48644
|
+
if (config.testCommand) {
|
|
48645
|
+
configLine2 += ` \u2502 Test: ${colors__default["default"].gray(config.testCommand)}`;
|
|
48646
|
+
}
|
|
48647
|
+
lines.push(configLine2);
|
|
48648
|
+
// --- Separator ---
|
|
48649
|
+
lines.push(sep);
|
|
48650
|
+
// --- Progress ---
|
|
48651
|
+
const progressSummary = [
|
|
48652
|
+
`${progress.sessionDone}/${progress.sessionTotal} Prompts (${progress.totalPrompts} total)`,
|
|
48653
|
+
`${progress.elapsedText}/${progress.estimatedTotalText}`,
|
|
48654
|
+
`Est. done ${progress.estimatedLabel}`,
|
|
48655
|
+
].join(' \u2502 ');
|
|
48656
|
+
lines.push(progressSummary);
|
|
48657
|
+
lines.push(buildProgressBar(progress.percentage));
|
|
48658
|
+
// --- Separator ---
|
|
48659
|
+
lines.push(sep);
|
|
48660
|
+
// --- Current prompt ---
|
|
48661
|
+
if (currentPromptLabel) {
|
|
48662
|
+
const spinnerPrefix = isActive ? colors__default["default"].yellow(`${spinner} `) : ' ';
|
|
48663
|
+
lines.push(spinnerPrefix + colors__default["default"].bold(currentPromptLabel));
|
|
48664
|
+
lines.push(colors__default["default"].gray(`Attempt ${currentAttempt}/${maxAttempts} \u2502 ${statusMessage}`));
|
|
48665
|
+
}
|
|
48666
|
+
else {
|
|
48667
|
+
lines.push(colors__default["default"].gray(statusMessage));
|
|
48668
|
+
}
|
|
48669
|
+
// --- Agent output ---
|
|
48670
|
+
if (agentOutputLines.length > 0) {
|
|
48671
|
+
lines.push('');
|
|
48672
|
+
lines.push(colors__default["default"].gray.bold('Agent output:'));
|
|
48673
|
+
const visibleLines = agentOutputLines.slice(-MAX_VISIBLE_OUTPUT_LINES);
|
|
48674
|
+
for (const line of visibleLines) {
|
|
48675
|
+
const cleanLine = stripAnsi(line);
|
|
48676
|
+
// Truncate to terminal width.
|
|
48677
|
+
const truncated = cleanLine.length > w - 2 ? cleanLine.slice(0, w - 5) + '...' : cleanLine;
|
|
48678
|
+
lines.push(colors__default["default"].gray(truncated));
|
|
48679
|
+
}
|
|
48680
|
+
}
|
|
48681
|
+
// --- Errors ---
|
|
48682
|
+
if (errors.length > 0) {
|
|
48683
|
+
lines.push('');
|
|
48684
|
+
for (const err of errors) {
|
|
48685
|
+
lines.push(colors__default["default"].red(`\u2717 ${err}`));
|
|
48686
|
+
}
|
|
48687
|
+
}
|
|
48688
|
+
// --- Separator ---
|
|
48689
|
+
lines.push(sep);
|
|
48690
|
+
// --- Controls ---
|
|
48691
|
+
const pauseLabel = isPaused
|
|
48692
|
+
? colors__default["default"].bgYellow.black(' PAUSED ') + colors__default["default"].gray(' [P] Resume \u2502 Ctrl+C Exit')
|
|
48693
|
+
: colors__default["default"].gray('[P] Pause \u2502 Ctrl+C Exit');
|
|
48694
|
+
lines.push(pauseLabel);
|
|
48695
|
+
return lines;
|
|
48696
|
+
}
|
|
48697
|
+
// Initial render.
|
|
48698
|
+
process.stdout.write('\n');
|
|
48699
|
+
render();
|
|
48700
|
+
const interval = setInterval(scheduleRender, UI_REFRESH_INTERVAL_MS);
|
|
48701
|
+
// Listen for state changes and schedule a re-render (debounced).
|
|
48702
|
+
state.on('change', scheduleRender);
|
|
48703
|
+
// --- Cleanup ---
|
|
48704
|
+
function cleanup() {
|
|
48705
|
+
clearInterval(interval);
|
|
48706
|
+
state.off('change', scheduleRender);
|
|
48707
|
+
process.stdin.off('keypress', keypressHandler);
|
|
48708
|
+
if (process.stdin.isTTY) {
|
|
48709
|
+
process.stdin.setRawMode(false);
|
|
48710
|
+
}
|
|
48711
|
+
isCapturing = false;
|
|
48712
|
+
console.info = originalConsoleInfo;
|
|
48713
|
+
console.warn = originalConsoleWarn;
|
|
48714
|
+
console.error = originalConsoleError;
|
|
48715
|
+
console.log = originalConsoleLog;
|
|
48716
|
+
// Render one final frame so the user sees the last state.
|
|
48717
|
+
render();
|
|
48718
|
+
process.stdout.write('\n');
|
|
48719
|
+
}
|
|
48720
|
+
return {
|
|
48721
|
+
state,
|
|
48722
|
+
startCapturingAgentOutput() {
|
|
48723
|
+
isCapturing = true;
|
|
48724
|
+
},
|
|
48725
|
+
stopCapturingAgentOutput() {
|
|
48726
|
+
isCapturing = false;
|
|
48727
|
+
},
|
|
48728
|
+
cleanup,
|
|
48729
|
+
};
|
|
48730
|
+
}
|
|
48731
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
48732
|
+
|
|
47866
48733
|
/**
|
|
47867
48734
|
* Constant for prompts dir.
|
|
47868
48735
|
*/
|
|
@@ -47925,8 +48792,13 @@
|
|
|
47925
48792
|
`));
|
|
47926
48793
|
}
|
|
47927
48794
|
const runStartDate = moment__default["default"]();
|
|
47928
|
-
const
|
|
47929
|
-
|
|
48795
|
+
const isUiMode = !options.dryRun && Boolean(process.stdout.isTTY);
|
|
48796
|
+
const progressDisplay = options.dryRun || isUiMode ? undefined : new CliProgressDisplay(runStartDate);
|
|
48797
|
+
const uiHandle = isUiMode ? renderCoderRunUi(runStartDate) : undefined;
|
|
48798
|
+
// When the Ink UI is active it handles keyboard input itself, so skip the raw stdin listener.
|
|
48799
|
+
if (!isUiMode) {
|
|
48800
|
+
listenForPause();
|
|
48801
|
+
}
|
|
47930
48802
|
try {
|
|
47931
48803
|
const resolvedCoderContext = await resolveCoderContext(options.context, process.cwd());
|
|
47932
48804
|
if (options.dryRun) {
|
|
@@ -48025,35 +48897,78 @@
|
|
|
48025
48897
|
}
|
|
48026
48898
|
console.info(colors__default["default"].green(`Running prompts with ${runner.name}`));
|
|
48027
48899
|
const runnerMetadata = getRunnerMetadata(options, actualRunnerModel);
|
|
48900
|
+
// Feed configuration into the terminal UI
|
|
48901
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setConfig({
|
|
48902
|
+
agentName: runner.name,
|
|
48903
|
+
modelName: actualRunnerModel,
|
|
48904
|
+
thinkingLevel: options.thinkingLevel,
|
|
48905
|
+
context: options.context,
|
|
48906
|
+
priority: options.priority,
|
|
48907
|
+
testCommand: options.testCommand,
|
|
48908
|
+
});
|
|
48909
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
48910
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Running prompts with ${runner.name}`);
|
|
48028
48911
|
let hasShownUpcomingTasks = false;
|
|
48029
48912
|
let hasWaitedForStart = false;
|
|
48030
48913
|
while (just(true)) {
|
|
48031
|
-
await checkPause(
|
|
48914
|
+
await checkPause({
|
|
48915
|
+
silent: isUiMode,
|
|
48916
|
+
onPaused: () => {
|
|
48917
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
48918
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('paused');
|
|
48919
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Paused');
|
|
48920
|
+
},
|
|
48921
|
+
onResumed: () => {
|
|
48922
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48923
|
+
},
|
|
48924
|
+
});
|
|
48925
|
+
if (isUiMode) {
|
|
48926
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
48927
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Loading prompts...');
|
|
48928
|
+
}
|
|
48032
48929
|
const promptFiles = await loadPromptFiles(PROMPTS_DIR$1);
|
|
48033
48930
|
const stats = summarizePrompts(promptFiles, options.priority);
|
|
48034
48931
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|
|
48035
|
-
|
|
48932
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(stats);
|
|
48933
|
+
if (!isUiMode) {
|
|
48934
|
+
printStats(stats, options.priority);
|
|
48935
|
+
}
|
|
48036
48936
|
const nextPrompt = findNextTodoPrompt(promptFiles, options.priority);
|
|
48037
48937
|
if (!hasShownUpcomingTasks) {
|
|
48038
|
-
if (stats.toBeWritten > 0) {
|
|
48938
|
+
if (stats.toBeWritten > 0 && !isUiMode) {
|
|
48039
48939
|
console.info(colors__default["default"].yellow('Following prompts need to be written:'));
|
|
48040
48940
|
printPromptsToBeWritten(promptFiles, options.priority);
|
|
48041
48941
|
console.info('');
|
|
48042
48942
|
}
|
|
48043
|
-
|
|
48943
|
+
if (!isUiMode) {
|
|
48944
|
+
printUpcomingTasks(listUpcomingTasks(promptFiles, options.priority));
|
|
48945
|
+
}
|
|
48044
48946
|
hasShownUpcomingTasks = true;
|
|
48045
48947
|
}
|
|
48046
48948
|
if (!nextPrompt) {
|
|
48047
48949
|
if (stats.toBeWritten > 0) {
|
|
48048
|
-
|
|
48950
|
+
const message = 'No prompts ready for agent.';
|
|
48951
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
48952
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
48953
|
+
if (!isUiMode) {
|
|
48954
|
+
console.info(colors__default["default"].yellow(message));
|
|
48955
|
+
}
|
|
48049
48956
|
}
|
|
48050
48957
|
else {
|
|
48051
|
-
|
|
48958
|
+
const message = 'All prompts are done.';
|
|
48959
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(message);
|
|
48960
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('done');
|
|
48961
|
+
if (!isUiMode) {
|
|
48962
|
+
console.info(colors__default["default"].green(message));
|
|
48963
|
+
}
|
|
48052
48964
|
}
|
|
48053
48965
|
return;
|
|
48054
48966
|
}
|
|
48055
48967
|
if (options.waitForUser) {
|
|
48968
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
48969
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(hasWaitedForStart ? 'Waiting... Press Enter to continue' : 'Waiting... Press Enter to start');
|
|
48056
48970
|
await waitForPromptStart(nextPrompt.file, nextPrompt.section, !hasWaitedForStart);
|
|
48971
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48057
48972
|
hasWaitedForStart = true;
|
|
48058
48973
|
}
|
|
48059
48974
|
if (!options.ignoreGitChanges) {
|
|
@@ -48063,29 +48978,57 @@
|
|
|
48063
48978
|
const codexPrompt = appendCoderContext(buildCodexPrompt(nextPrompt.file, nextPrompt.section), resolvedCoderContext);
|
|
48064
48979
|
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
48065
48980
|
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
48066
|
-
|
|
48981
|
+
if (isUiMode) {
|
|
48982
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentPrompt(promptLabel);
|
|
48983
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('running');
|
|
48984
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Running');
|
|
48985
|
+
}
|
|
48986
|
+
else {
|
|
48987
|
+
console.info(colors__default["default"].blue(`Processing ${promptLabel}`));
|
|
48988
|
+
}
|
|
48067
48989
|
const promptExecutionStartedDate = moment__default["default"]();
|
|
48990
|
+
let attemptCount = 1;
|
|
48068
48991
|
const roundChangedFilesSnapshot = options.normalizeLineEndings
|
|
48069
48992
|
? await captureChangedFilesSnapshot(process.cwd())
|
|
48070
48993
|
: undefined;
|
|
48071
48994
|
try {
|
|
48072
|
-
|
|
48995
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
48996
|
+
const result = await runPromptWithTestFeedback({
|
|
48997
|
+
runner,
|
|
48073
48998
|
prompt: codexPrompt,
|
|
48074
48999
|
scriptPath,
|
|
48075
49000
|
projectPath: process.cwd(),
|
|
49001
|
+
promptLabel,
|
|
49002
|
+
testCommand: options.testCommand,
|
|
49003
|
+
onAttemptStarted: (nextAttemptCount) => {
|
|
49004
|
+
attemptCount = nextAttemptCount;
|
|
49005
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(nextAttemptCount);
|
|
49006
|
+
if (nextAttemptCount > 1) {
|
|
49007
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Retrying (attempt ${nextAttemptCount})`);
|
|
49008
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('verifying');
|
|
49009
|
+
}
|
|
49010
|
+
},
|
|
48076
49011
|
});
|
|
48077
|
-
|
|
49012
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49013
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Committing changes');
|
|
49014
|
+
markPromptDone(nextPrompt.file, nextPrompt.section, result.usage, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, result.attemptCount);
|
|
48078
49015
|
await writePromptFile(nextPrompt.file);
|
|
48079
49016
|
await normalizeLineEndingsForCurrentRound(options, roundChangedFilesSnapshot);
|
|
48080
49017
|
if (options.waitForUser) {
|
|
49018
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.pauseTimer();
|
|
49019
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage('Waiting... Press Enter to commit');
|
|
48081
49020
|
printCommitMessage(commitMessage);
|
|
48082
49021
|
await waitForEnter(colors__default["default"].bgWhite('Press Enter to commit and continue...'));
|
|
49022
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.resumeTimer();
|
|
48083
49023
|
}
|
|
48084
|
-
await commitChanges(commitMessage, {
|
|
49024
|
+
await commitChanges(commitMessage, { autoPush: options.autoPush });
|
|
48085
49025
|
await runPostPromptAutoMigrationIfEnabled(options);
|
|
48086
49026
|
}
|
|
48087
49027
|
catch (error) {
|
|
48088
|
-
|
|
49028
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
49029
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
49030
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
49031
|
+
markPromptFailed(nextPrompt.file, nextPrompt.section, runnerMetadata.runnerName, runnerMetadata.modelName, promptExecutionStartedDate, attemptCount);
|
|
48089
49032
|
await writePromptFile(nextPrompt.file);
|
|
48090
49033
|
await writePromptErrorLog({
|
|
48091
49034
|
file: nextPrompt.file,
|
|
@@ -48101,6 +49044,7 @@
|
|
|
48101
49044
|
}
|
|
48102
49045
|
finally {
|
|
48103
49046
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.stop();
|
|
49047
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.cleanup();
|
|
48104
49048
|
if (!options.dryRun) {
|
|
48105
49049
|
printAgentGitIdentityTipIfNeeded();
|
|
48106
49050
|
}
|
|
@@ -48162,24 +49106,26 @@
|
|
|
48162
49106
|
*/
|
|
48163
49107
|
const MAX_PENDING_FILE_NAMES = 8;
|
|
48164
49108
|
/**
|
|
48165
|
-
*
|
|
49109
|
+
* Default verification options parsed from the current process arguments.
|
|
48166
49110
|
*/
|
|
48167
|
-
const
|
|
49111
|
+
const DEFAULT_VERIFY_PROMPTS_OPTIONS = normalizeVerifyPromptsOptions(parseVerifyPromptsCliOptions(process.argv.slice(2)));
|
|
48168
49112
|
/**
|
|
48169
49113
|
* Starts the verification loop and exits when no `[ ]` prompts remain.
|
|
48170
49114
|
*
|
|
48171
|
-
* @param reverse - Process files in reverse order
|
|
48172
|
-
*
|
|
48173
49115
|
* @public exported from `@promptbook/cli`
|
|
48174
49116
|
*/
|
|
48175
|
-
async function verifyPrompts(
|
|
49117
|
+
async function verifyPrompts(options = DEFAULT_VERIFY_PROMPTS_OPTIONS) {
|
|
49118
|
+
const normalizedOptions = normalizeVerifyPromptsOptions(options);
|
|
48176
49119
|
console.info(colors__default["default"].cyan.bold('📋 Prompt verification helper'));
|
|
48177
|
-
if (reverse) {
|
|
49120
|
+
if (normalizedOptions.reverse) {
|
|
48178
49121
|
console.info(colors__default["default"].gray('Processing files in reverse order'));
|
|
48179
49122
|
}
|
|
48180
|
-
|
|
48181
|
-
|
|
48182
|
-
|
|
49123
|
+
if (normalizedOptions.ignore.length > 0) {
|
|
49124
|
+
console.info(colors__default["default"].gray(`Ignoring candidates matching: ${normalizedOptions.ignore.join(', ')}`));
|
|
49125
|
+
}
|
|
49126
|
+
const { promptFiles: initialFiles, ignoredPromptFiles } = await loadPromptFilesForVerification(normalizedOptions);
|
|
49127
|
+
if (ignoredPromptFiles.length > 0) {
|
|
49128
|
+
console.info(colors__default["default"].gray(`Ignored ${ignoredPromptFiles.length} prompt file(s) for this run.`));
|
|
48183
49129
|
}
|
|
48184
49130
|
displayTopLevelFileList(initialFiles);
|
|
48185
49131
|
await prepareArchiveDirectory();
|
|
@@ -48194,10 +49140,7 @@
|
|
|
48194
49140
|
if (wasSkipped) {
|
|
48195
49141
|
skippedFiles.add(fileWithAllDone.path);
|
|
48196
49142
|
}
|
|
48197
|
-
promptFiles = await
|
|
48198
|
-
if (REVERSE_ORDER) {
|
|
48199
|
-
promptFiles.reverse();
|
|
48200
|
-
}
|
|
49143
|
+
promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
|
|
48201
49144
|
continue;
|
|
48202
49145
|
}
|
|
48203
49146
|
// Second priority: process todo prompts
|
|
@@ -48207,11 +49150,56 @@
|
|
|
48207
49150
|
break;
|
|
48208
49151
|
}
|
|
48209
49152
|
await resolvePrompt(nextPrompt);
|
|
48210
|
-
promptFiles = await
|
|
48211
|
-
|
|
48212
|
-
|
|
49153
|
+
promptFiles = (await loadPromptFilesForVerification(normalizedOptions)).promptFiles;
|
|
49154
|
+
}
|
|
49155
|
+
}
|
|
49156
|
+
/**
|
|
49157
|
+
* Parses supported command-line arguments for the standalone verification script.
|
|
49158
|
+
*/
|
|
49159
|
+
function parseVerifyPromptsCliOptions(args) {
|
|
49160
|
+
return {
|
|
49161
|
+
reverse: args.includes('--reverse'),
|
|
49162
|
+
ignore: readRepeatableStringOption(args, '--ignore'),
|
|
49163
|
+
};
|
|
49164
|
+
}
|
|
49165
|
+
/**
|
|
49166
|
+
* Loads prompt files and applies ordering plus ignore filters for one verification pass.
|
|
49167
|
+
*/
|
|
49168
|
+
async function loadPromptFilesForVerification(options) {
|
|
49169
|
+
const loadedPromptFiles = await loadPromptFiles(PROMPTS_DIR);
|
|
49170
|
+
const { promptFiles, ignoredPromptFiles } = partitionPromptFilesByIgnore(loadedPromptFiles, options.ignore);
|
|
49171
|
+
if (options.reverse) {
|
|
49172
|
+
promptFiles.reverse();
|
|
49173
|
+
}
|
|
49174
|
+
return { promptFiles, ignoredPromptFiles };
|
|
49175
|
+
}
|
|
49176
|
+
/**
|
|
49177
|
+
* Splits prompt files into files that should be verified now and files ignored for this run.
|
|
49178
|
+
*
|
|
49179
|
+
* @public exported from `@promptbook/cli`
|
|
49180
|
+
*/
|
|
49181
|
+
function partitionPromptFilesByIgnore(promptFiles, ignoreValues) {
|
|
49182
|
+
const normalizedIgnoreValues = normalizeIgnoreValues(ignoreValues);
|
|
49183
|
+
if (normalizedIgnoreValues.length === 0) {
|
|
49184
|
+
return {
|
|
49185
|
+
promptFiles: [...promptFiles],
|
|
49186
|
+
ignoredPromptFiles: [],
|
|
49187
|
+
};
|
|
49188
|
+
}
|
|
49189
|
+
const promptFilesToVerify = [];
|
|
49190
|
+
const ignoredPromptFiles = [];
|
|
49191
|
+
for (const promptFile of promptFiles) {
|
|
49192
|
+
if (matchesIgnoredPromptFile(promptFile, normalizedIgnoreValues)) {
|
|
49193
|
+
ignoredPromptFiles.push(promptFile);
|
|
49194
|
+
}
|
|
49195
|
+
else {
|
|
49196
|
+
promptFilesToVerify.push(promptFile);
|
|
48213
49197
|
}
|
|
48214
49198
|
}
|
|
49199
|
+
return {
|
|
49200
|
+
promptFiles: promptFilesToVerify,
|
|
49201
|
+
ignoredPromptFiles,
|
|
49202
|
+
};
|
|
48215
49203
|
}
|
|
48216
49204
|
/**
|
|
48217
49205
|
* Ensures the destination directory for completed prompts exists.
|
|
@@ -48219,13 +49207,92 @@
|
|
|
48219
49207
|
async function prepareArchiveDirectory() {
|
|
48220
49208
|
await promises.mkdir(DONE_PROMPTS_DIR, { recursive: true });
|
|
48221
49209
|
}
|
|
49210
|
+
/**
|
|
49211
|
+
* Normalizes verification options so the rest of the flow can assume stable defaults.
|
|
49212
|
+
*/
|
|
49213
|
+
function normalizeVerifyPromptsOptions(options) {
|
|
49214
|
+
var _a, _b;
|
|
49215
|
+
return {
|
|
49216
|
+
reverse: (_a = options.reverse) !== null && _a !== void 0 ? _a : false,
|
|
49217
|
+
ignore: normalizeIgnoreValues((_b = options.ignore) !== null && _b !== void 0 ? _b : []),
|
|
49218
|
+
};
|
|
49219
|
+
}
|
|
49220
|
+
/**
|
|
49221
|
+
* Normalizes ignore values and removes empty or duplicate entries case-insensitively.
|
|
49222
|
+
*/
|
|
49223
|
+
function normalizeIgnoreValues(ignoreValues) {
|
|
49224
|
+
const normalizedIgnoreValues = [];
|
|
49225
|
+
const seenIgnoreValues = new Set();
|
|
49226
|
+
for (const ignoreValue of ignoreValues) {
|
|
49227
|
+
const trimmedIgnoreValue = ignoreValue.trim();
|
|
49228
|
+
if (!trimmedIgnoreValue) {
|
|
49229
|
+
continue;
|
|
49230
|
+
}
|
|
49231
|
+
const lowerCasedIgnoreValue = trimmedIgnoreValue.toLowerCase();
|
|
49232
|
+
if (seenIgnoreValues.has(lowerCasedIgnoreValue)) {
|
|
49233
|
+
continue;
|
|
49234
|
+
}
|
|
49235
|
+
seenIgnoreValues.add(lowerCasedIgnoreValue);
|
|
49236
|
+
normalizedIgnoreValues.push(trimmedIgnoreValue);
|
|
49237
|
+
}
|
|
49238
|
+
return normalizedIgnoreValues;
|
|
49239
|
+
}
|
|
49240
|
+
/**
|
|
49241
|
+
* Reads one repeatable string option from raw CLI arguments.
|
|
49242
|
+
*/
|
|
49243
|
+
function readRepeatableStringOption(args, flag) {
|
|
49244
|
+
const values = [];
|
|
49245
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
49246
|
+
const argument = args[index];
|
|
49247
|
+
if (!argument) {
|
|
49248
|
+
continue;
|
|
49249
|
+
}
|
|
49250
|
+
if (argument === flag) {
|
|
49251
|
+
const nextValue = args[index + 1];
|
|
49252
|
+
if (nextValue !== undefined && !nextValue.startsWith('--')) {
|
|
49253
|
+
values.push(nextValue);
|
|
49254
|
+
index += 1;
|
|
49255
|
+
}
|
|
49256
|
+
continue;
|
|
49257
|
+
}
|
|
49258
|
+
if (argument.startsWith(`${flag}=`)) {
|
|
49259
|
+
values.push(argument.slice(flag.length + 1));
|
|
49260
|
+
}
|
|
49261
|
+
}
|
|
49262
|
+
return values;
|
|
49263
|
+
}
|
|
49264
|
+
/**
|
|
49265
|
+
* Resolves whether a prompt file should be ignored for this verification run.
|
|
49266
|
+
*/
|
|
49267
|
+
function matchesIgnoredPromptFile(promptFile, ignoreValues) {
|
|
49268
|
+
const searchableValues = [promptFile.name, getPromptFileFirstLine(promptFile)].map((value) => value.toLowerCase());
|
|
49269
|
+
return ignoreValues.some((ignoreValue) => {
|
|
49270
|
+
const lowerCasedIgnoreValue = ignoreValue.toLowerCase();
|
|
49271
|
+
return searchableValues.some((searchableValue) => searchableValue.includes(lowerCasedIgnoreValue));
|
|
49272
|
+
});
|
|
49273
|
+
}
|
|
49274
|
+
/**
|
|
49275
|
+
* Returns the first meaningful line of the prompt file after the status line.
|
|
49276
|
+
*/
|
|
49277
|
+
function getPromptFileFirstLine(promptFile) {
|
|
49278
|
+
var _a;
|
|
49279
|
+
const firstSection = promptFile.sections[0];
|
|
49280
|
+
const startLineIndex = (firstSection === null || firstSection === void 0 ? void 0 : firstSection.statusLineIndex) !== undefined ? firstSection.statusLineIndex + 1 : ((_a = firstSection === null || firstSection === void 0 ? void 0 : firstSection.startLine) !== null && _a !== void 0 ? _a : 0);
|
|
49281
|
+
for (let index = startLineIndex; index < promptFile.lines.length; index += 1) {
|
|
49282
|
+
const line = promptFile.lines[index];
|
|
49283
|
+
if (line !== undefined && line.trim() !== '') {
|
|
49284
|
+
return line.trim();
|
|
49285
|
+
}
|
|
49286
|
+
}
|
|
49287
|
+
return '';
|
|
49288
|
+
}
|
|
48222
49289
|
/**
|
|
48223
49290
|
* Displays the list of files that currently live in the prompts root.
|
|
48224
49291
|
*/
|
|
48225
49292
|
function displayTopLevelFileList(promptFiles) {
|
|
48226
49293
|
console.info(colors__default["default"].cyan('\nTop-level prompt files:'));
|
|
48227
49294
|
if (!promptFiles.length) {
|
|
48228
|
-
console.info(colors__default["default"].gray(' (no markdown files found in prompts/)'));
|
|
49295
|
+
console.info(colors__default["default"].gray(' (no prompt markdown files found for this run in prompts/)'));
|
|
48229
49296
|
return;
|
|
48230
49297
|
}
|
|
48231
49298
|
for (const file of promptFiles) {
|
|
@@ -48542,7 +49609,7 @@
|
|
|
48542
49609
|
}
|
|
48543
49610
|
// Note: When run as a standalone script, call the exported function
|
|
48544
49611
|
if (require.main === module) {
|
|
48545
|
-
verifyPrompts(
|
|
49612
|
+
verifyPrompts(DEFAULT_VERIFY_PROMPTS_OPTIONS).catch((error) => {
|
|
48546
49613
|
console.error(colors__default["default"].bgRed('Prompt verification failed:'), error);
|
|
48547
49614
|
process.exit(1);
|
|
48548
49615
|
});
|
|
@@ -48550,7 +49617,8 @@
|
|
|
48550
49617
|
|
|
48551
49618
|
var verifyPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
48552
49619
|
__proto__: null,
|
|
48553
|
-
verifyPrompts: verifyPrompts
|
|
49620
|
+
verifyPrompts: verifyPrompts,
|
|
49621
|
+
partitionPromptFilesByIgnore: partitionPromptFilesByIgnore
|
|
48554
49622
|
});
|
|
48555
49623
|
|
|
48556
49624
|
/**
|
|
@@ -49599,7 +50667,7 @@
|
|
|
49599
50667
|
/**
|
|
49600
50668
|
* Constant for default agent kit model name.
|
|
49601
50669
|
*/
|
|
49602
|
-
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-
|
|
50670
|
+
const DEFAULT_AGENT_KIT_MODEL_NAME = 'gpt-5.4-mini';
|
|
49603
50671
|
/**
|
|
49604
50672
|
* Creates one structured log entry for streamed tool-call updates.
|
|
49605
50673
|
*
|
|
@@ -50649,6 +51717,7 @@
|
|
|
50649
51717
|
* @param agentSource The agent source string that defines the agent's behavior
|
|
50650
51718
|
*/
|
|
50651
51719
|
constructor(options) {
|
|
51720
|
+
var _a;
|
|
50652
51721
|
this.options = options;
|
|
50653
51722
|
/**
|
|
50654
51723
|
* Cached model requirements to avoid re-parsing the agent source
|
|
@@ -50658,6 +51727,7 @@
|
|
|
50658
51727
|
* Cached parsed agent information
|
|
50659
51728
|
*/
|
|
50660
51729
|
this._cachedAgentInfo = null;
|
|
51730
|
+
this.precomputedModelRequirements = (_a = options.precomputedModelRequirements) !== null && _a !== void 0 ? _a : null;
|
|
50661
51731
|
}
|
|
50662
51732
|
/**
|
|
50663
51733
|
* Updates the agent source and clears the cache
|
|
@@ -50665,9 +51735,13 @@
|
|
|
50665
51735
|
* @param agentSource The new agent source string
|
|
50666
51736
|
*/
|
|
50667
51737
|
updateAgentSource(agentSource) {
|
|
51738
|
+
if (this.options.agentSource === agentSource) {
|
|
51739
|
+
return;
|
|
51740
|
+
}
|
|
50668
51741
|
this.options.agentSource = agentSource;
|
|
50669
51742
|
this._cachedAgentInfo = null;
|
|
50670
51743
|
this._cachedModelRequirements = null;
|
|
51744
|
+
this.precomputedModelRequirements = null;
|
|
50671
51745
|
}
|
|
50672
51746
|
/**
|
|
50673
51747
|
* Get cached or parse agent information
|
|
@@ -50684,6 +51758,16 @@
|
|
|
50684
51758
|
* Note: [🐤] This is names `getModelRequirements` *(not `getAgentModelRequirements`)* because in future these two will be united
|
|
50685
51759
|
*/
|
|
50686
51760
|
async getModelRequirements() {
|
|
51761
|
+
var _a, _b;
|
|
51762
|
+
if (this.precomputedModelRequirements !== null) {
|
|
51763
|
+
if (this.options.isVerbose) {
|
|
51764
|
+
console.info('[🤰]', 'Using precomputed agent model requirements', {
|
|
51765
|
+
agent: this.title,
|
|
51766
|
+
toolCount: (_b = (_a = this.precomputedModelRequirements.tools) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0,
|
|
51767
|
+
});
|
|
51768
|
+
}
|
|
51769
|
+
return this.precomputedModelRequirements;
|
|
51770
|
+
}
|
|
50687
51771
|
if (this._cachedModelRequirements === null) {
|
|
50688
51772
|
const preparationStartedAtMs = Date.now();
|
|
50689
51773
|
if (this.options.isVerbose) {
|
|
@@ -50793,6 +51877,7 @@
|
|
|
50793
51877
|
* Resolves agent requirements, attachments, and runtime overrides into one forwarded chat prompt.
|
|
50794
51878
|
*/
|
|
50795
51879
|
async prepareChatPrompt(prompt) {
|
|
51880
|
+
var _a;
|
|
50796
51881
|
const chatPrompt = this.requireChatPrompt(prompt);
|
|
50797
51882
|
const { sanitizedRequirements, promptSuffix } = await this.getSanitizedAgentModelRequirements();
|
|
50798
51883
|
const attachments = normalizeChatAttachments(chatPrompt.attachments);
|
|
@@ -50810,7 +51895,16 @@
|
|
|
50810
51895
|
mergedTools,
|
|
50811
51896
|
knowledgeSourcesForAgent,
|
|
50812
51897
|
});
|
|
50813
|
-
|
|
51898
|
+
if (this.options.isVerbose) {
|
|
51899
|
+
console.info('[🤰]', 'Prepared agent chat prompt', {
|
|
51900
|
+
agent: this.title,
|
|
51901
|
+
usedPrecomputedModelRequirements: this.precomputedModelRequirements !== null,
|
|
51902
|
+
toolNames: mergedTools.map((tool) => tool.name),
|
|
51903
|
+
knowledgeSourcesCount: (_a = knowledgeSourcesForAgent === null || knowledgeSourcesForAgent === void 0 ? void 0 : knowledgeSourcesForAgent.length) !== null && _a !== void 0 ? _a : 0,
|
|
51904
|
+
promptSuffixLength: promptSuffix.length,
|
|
51905
|
+
systemMessageLength: sanitizedRequirements.systemMessage.length,
|
|
51906
|
+
});
|
|
51907
|
+
}
|
|
50814
51908
|
return {
|
|
50815
51909
|
forwardedPrompt,
|
|
50816
51910
|
sanitizedRequirements,
|
|
@@ -50997,6 +52091,7 @@
|
|
|
50997
52091
|
* Runs one prepared prompt through the deprecated OpenAI Assistant backend.
|
|
50998
52092
|
*/
|
|
50999
52093
|
async callOpenAiAssistantChatModelStream(options) {
|
|
52094
|
+
var _a, _b, _c, _d;
|
|
51000
52095
|
const assistant = await this.getOrPrepareOpenAiAssistant({
|
|
51001
52096
|
llmTools: options.llmTools,
|
|
51002
52097
|
originalPrompt: options.originalPrompt,
|
|
@@ -51004,7 +52099,14 @@
|
|
|
51004
52099
|
onProgress: options.onProgress,
|
|
51005
52100
|
});
|
|
51006
52101
|
const promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools = createOpenAiAssistantPrompt(options.preparedChatPrompt.forwardedPrompt);
|
|
51007
|
-
|
|
52102
|
+
if (this.options.isVerbose) {
|
|
52103
|
+
console.info('[🤰]', 'Prepared OpenAI Assistant prompt', {
|
|
52104
|
+
agent: this.title,
|
|
52105
|
+
toolNames: (_b = (_a = promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools.modelRequirements.tools) === null || _a === void 0 ? void 0 : _a.map((tool) => tool.name)) !== null && _b !== void 0 ? _b : [],
|
|
52106
|
+
knowledgeSourcesCount: (_d = (_c = promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools.modelRequirements
|
|
52107
|
+
.knowledgeSources) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0,
|
|
52108
|
+
});
|
|
52109
|
+
}
|
|
51008
52110
|
return assistant.callChatModelStream(promptWithAgentModelRequirementsForOpenAiAssistantExecutionTools, options.onProgress, options.streamOptions);
|
|
51009
52111
|
}
|
|
51010
52112
|
/**
|
|
@@ -51695,7 +52797,8 @@
|
|
|
51695
52797
|
isVerbose: options.isVerbose,
|
|
51696
52798
|
llmTools: getSingleLlmExecutionTools(options.executionTools.llm),
|
|
51697
52799
|
assistantPreparationMode: options.assistantPreparationMode,
|
|
51698
|
-
agentSource: agentSource.value,
|
|
52800
|
+
agentSource: agentSource.value,
|
|
52801
|
+
precomputedModelRequirements: options.precomputedModelRequirements,
|
|
51699
52802
|
});
|
|
51700
52803
|
this._agentName = undefined;
|
|
51701
52804
|
/**
|