@promptbook/cli 0.114.0-33 → 0.114.0-34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.es.js +1254 -318
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/common/createFreeDiskSpaceGuard.d.ts +25 -0
- package/esm/scripts/run-codex-prompts/common/formatUnknownErrorDetails.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +21 -3
- package/esm/scripts/run-codex-prompts/main/listCoderPrompts.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/buildPromptRunTraceContent.d.ts +77 -0
- package/esm/scripts/run-codex-prompts/prompts/buildPromptRunTracePath.d.ts +10 -0
- package/esm/scripts/run-codex-prompts/prompts/isPromptCompatibleWithRunner.d.ts +11 -6
- package/esm/scripts/run-codex-prompts/prompts/loadPromptFiles.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/writePromptRunTrace.d.ts +19 -0
- package/esm/scripts/run-codex-prompts/runners/common/buildHarnessAuthenticationError.d.ts +20 -0
- package/esm/scripts/run-codex-prompts/runners/common/createAuthenticationAwarePromptRunner.d.ts +11 -0
- package/esm/scripts/run-codex-prompts/runners/common/extractHarnessAuthenticationFailureReason.d.ts +9 -0
- package/esm/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +3 -0
- package/esm/src/book-2.0/book-language-documentation/getSafeCodeBlock.d.ts +1 -1
- package/esm/src/book-components/Chat/MockedChat/MockedChat.test.d.ts +2 -0
- package/esm/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.d.ts +2 -1
- package/esm/src/cli/cli-commands/coder/agentCliOptions.d.ts +21 -0
- package/esm/src/cli/cli-commands/coder/boilerplateTemplates.d.ts +8 -21
- package/esm/src/cli/cli-commands/coder/coderReferencedArtifacts.d.ts +33 -0
- package/esm/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.d.ts +4 -2
- package/esm/src/cli/cli-commands/coder/ensureCoderVscodeSettingsFile.d.ts +2 -0
- package/esm/src/cli/cli-commands/coder/ensureDirectory.d.ts +6 -0
- package/esm/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.d.ts +6 -0
- package/esm/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +7 -5
- package/esm/src/cli/cli-commands/coder/mergeStringRecordJsonFile.d.ts +19 -1
- package/esm/src/cli/cli-commands/coder/printCoderRunFailure.d.ts +6 -0
- package/esm/src/cli/cli-commands/common/$askForConfirmation.d.ts +4 -2
- package/esm/src/cli/cli-commands/common/disk-space/$assertSufficientFreeDiskSpace.d.ts +12 -0
- package/esm/src/cli/cli-commands/common/disk-space/$assertSufficientFreeDiskSpace.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/disk-space/$readFreeDiskSpaceStatus.d.ts +11 -0
- package/esm/src/cli/cli-commands/common/disk-space/$readFreeDiskSpaceStatus.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/disk-space/FreeDiskSpaceStatus.d.ts +33 -0
- package/esm/src/cli/cli-commands/common/disk-space/formatFreeDiskSpaceBytes.d.ts +6 -0
- package/esm/src/cli/cli-commands/common/disk-space/formatFreeDiskSpaceBytes.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/disk-space/formatLowFreeDiskSpaceWarning.d.ts +10 -0
- package/esm/src/cli/cli-commands/common/disk-space/freeDiskSpaceConstants.d.ts +28 -0
- package/esm/src/cli/cli-commands/common/disk-space/resolveFreeDiskSpaceLevel.d.ts +7 -0
- package/esm/src/cli/cli-commands/common/disk-space/resolveFreeDiskSpaceLevel.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.d.ts +2 -1
- package/esm/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +3 -2
- package/esm/src/cli/cli-commands/common/harness/HarnessDefinition.d.ts +26 -0
- package/esm/src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.d.ts +4 -2
- package/esm/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.d.ts +2 -1
- package/esm/src/cli/cli-commands/common/questionsCliOptions.d.ts +45 -0
- package/esm/src/cli/cli-commands/common/questionsCliOptions.test.d.ts +1 -0
- package/esm/src/cli/common/$deprecateCliCommand.d.ts +3 -0
- package/esm/src/cli/common/$hideCliCommandFromHelp.d.ts +11 -0
- package/esm/src/cli/common/$hideCliCommandFromHelp.test.d.ts +1 -0
- package/esm/src/cli/common/$requireCliSubcommand.d.ts +18 -0
- package/esm/src/cli/common/$requireCliSubcommand.test.d.ts +1 -0
- package/esm/src/llm-providers/vercel/VercelExecutionToolsOptions.d.ts +5 -2
- package/esm/src/version.d.ts +1 -1
- package/package.json +8 -11
- package/src/book-2.0/book-language-documentation/getSafeCodeBlock.ts +1 -1
- package/src/book-components/Chat/MockedChat/MockedChat.tsx +25 -1
- package/src/cli/cli-commands/agent-folder.ts +2 -6
- package/src/cli/cli-commands/agent.ts +2 -6
- package/src/cli/cli-commands/agents-server.ts +2 -6
- package/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.ts +3 -0
- package/src/cli/cli-commands/coder/add.ts +27 -2
- package/src/cli/cli-commands/coder/agentCliOptions.ts +32 -0
- package/src/cli/cli-commands/coder/boilerplateTemplates.ts +17 -44
- package/src/cli/cli-commands/coder/coderReferencedArtifacts.ts +106 -0
- package/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.ts +4 -2
- package/src/cli/cli-commands/coder/ensureCoderVscodeSettingsFile.ts +5 -1
- package/src/cli/cli-commands/coder/ensureDirectory.ts +27 -1
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +99 -10
- package/src/cli/cli-commands/coder/init.ts +23 -14
- package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +18 -27
- package/src/cli/cli-commands/coder/list.ts +15 -3
- package/src/cli/cli-commands/coder/mergeStringRecordJsonFile.ts +31 -7
- package/src/cli/cli-commands/coder/ping.ts +25 -22
- package/src/cli/cli-commands/coder/printCoderRunFailure.ts +14 -0
- package/src/cli/cli-commands/coder/printInitializationSummary.ts +23 -16
- package/src/cli/cli-commands/coder/run.ts +34 -23
- package/src/cli/cli-commands/coder/server.ts +43 -32
- package/src/cli/cli-commands/coder.ts +2 -6
- package/src/cli/cli-commands/common/$askForConfirmation.ts +12 -2
- package/src/cli/cli-commands/common/disk-space/$assertSufficientFreeDiskSpace.ts +35 -0
- package/src/cli/cli-commands/common/disk-space/$readFreeDiskSpaceStatus.ts +37 -0
- package/src/cli/cli-commands/common/disk-space/FreeDiskSpaceStatus.ts +39 -0
- package/src/cli/cli-commands/common/disk-space/formatFreeDiskSpaceBytes.ts +26 -0
- package/src/cli/cli-commands/common/disk-space/formatLowFreeDiskSpaceWarning.ts +33 -0
- package/src/cli/cli-commands/common/disk-space/freeDiskSpaceConstants.ts +33 -0
- package/src/cli/cli-commands/common/disk-space/resolveFreeDiskSpaceLevel.ts +21 -0
- package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +17 -5
- package/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.ts +8 -3
- package/src/cli/cli-commands/common/harness/HarnessDefinition.ts +36 -0
- package/src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.ts +8 -3
- package/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.ts +13 -2
- package/src/cli/cli-commands/common/questionsCliOptions.ts +89 -0
- package/src/cli/cli-commands/run.ts +3 -1
- package/src/cli/common/$deprecateCliCommand.ts +5 -0
- package/src/cli/common/$hideCliCommandFromHelp.ts +27 -0
- package/src/cli/common/$requireCliSubcommand.ts +35 -0
- package/src/cli/promptbookCli.ts +13 -9
- package/src/llm-providers/vercel/VercelExecutionToolsOptions.ts +7 -2
- package/src/llm-providers/vercel/createExecutionToolsFromVercelProvider.ts +18 -17
- package/src/other/templates/getTemplatesPipelineCollection.ts +677 -881
- package/src/version.ts +2 -2
- package/src/versions.txt +1 -0
- package/umd/index.umd.js +1253 -317
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/common/createFreeDiskSpaceGuard.d.ts +25 -0
- package/umd/scripts/run-codex-prompts/common/formatUnknownErrorDetails.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/common/resolveCoderAgent.d.ts +21 -3
- package/umd/scripts/run-codex-prompts/main/listCoderPrompts.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/buildPromptRunTraceContent.d.ts +77 -0
- package/umd/scripts/run-codex-prompts/prompts/buildPromptRunTracePath.d.ts +10 -0
- package/umd/scripts/run-codex-prompts/prompts/isPromptCompatibleWithRunner.d.ts +11 -6
- package/umd/scripts/run-codex-prompts/prompts/loadPromptFiles.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/writePromptRunTrace.d.ts +19 -0
- package/umd/scripts/run-codex-prompts/runners/common/buildHarnessAuthenticationError.d.ts +20 -0
- package/umd/scripts/run-codex-prompts/runners/common/createAuthenticationAwarePromptRunner.d.ts +11 -0
- package/umd/scripts/run-codex-prompts/runners/common/extractHarnessAuthenticationFailureReason.d.ts +9 -0
- package/umd/scripts/run-codex-prompts/ui/buildCoderRunUiFrame.d.ts +3 -0
- package/umd/src/book-2.0/book-language-documentation/getSafeCodeBlock.d.ts +1 -1
- package/umd/src/book-components/Chat/MockedChat/MockedChat.test.d.ts +2 -0
- package/umd/src/cli/cli-commands/coder/$ensureCoderHarnessGitignoreRules.d.ts +2 -1
- package/umd/src/cli/cli-commands/coder/agentCliOptions.d.ts +21 -0
- package/umd/src/cli/cli-commands/coder/boilerplateTemplates.d.ts +8 -21
- package/umd/src/cli/cli-commands/coder/coderReferencedArtifacts.d.ts +33 -0
- package/umd/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.d.ts +4 -2
- package/umd/src/cli/cli-commands/coder/ensureCoderVscodeSettingsFile.d.ts +2 -0
- package/umd/src/cli/cli-commands/coder/ensureDirectory.d.ts +6 -0
- package/umd/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.d.ts +6 -0
- package/umd/src/cli/cli-commands/coder/init.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +7 -5
- package/umd/src/cli/cli-commands/coder/mergeStringRecordJsonFile.d.ts +19 -1
- package/umd/src/cli/cli-commands/coder/printCoderRunFailure.d.ts +6 -0
- package/umd/src/cli/cli-commands/common/$askForConfirmation.d.ts +4 -2
- package/umd/src/cli/cli-commands/common/$askForConfirmation.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/disk-space/$assertSufficientFreeDiskSpace.d.ts +12 -0
- package/umd/src/cli/cli-commands/common/disk-space/$assertSufficientFreeDiskSpace.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/disk-space/$readFreeDiskSpaceStatus.d.ts +11 -0
- package/umd/src/cli/cli-commands/common/disk-space/$readFreeDiskSpaceStatus.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/disk-space/FreeDiskSpaceStatus.d.ts +33 -0
- package/umd/src/cli/cli-commands/common/disk-space/formatFreeDiskSpaceBytes.d.ts +6 -0
- package/umd/src/cli/cli-commands/common/disk-space/formatFreeDiskSpaceBytes.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/disk-space/formatLowFreeDiskSpaceWarning.d.ts +10 -0
- package/umd/src/cli/cli-commands/common/disk-space/freeDiskSpaceConstants.d.ts +28 -0
- package/umd/src/cli/cli-commands/common/disk-space/resolveFreeDiskSpaceLevel.d.ts +7 -0
- package/umd/src/cli/cli-commands/common/disk-space/resolveFreeDiskSpaceLevel.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.d.ts +2 -1
- package/umd/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +3 -2
- package/umd/src/cli/cli-commands/common/harness/HarnessDefinition.d.ts +26 -0
- package/umd/src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.d.ts +4 -2
- package/umd/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.d.ts +2 -1
- package/umd/src/cli/cli-commands/common/questionsCliOptions.d.ts +45 -0
- package/umd/src/cli/cli-commands/common/questionsCliOptions.test.d.ts +1 -0
- package/umd/src/cli/common/$deprecateCliCommand.d.ts +3 -0
- package/umd/src/cli/common/$hideCliCommandFromHelp.d.ts +11 -0
- package/umd/src/cli/common/$hideCliCommandFromHelp.test.d.ts +1 -0
- package/umd/src/cli/common/$requireCliSubcommand.d.ts +18 -0
- package/umd/src/cli/common/$requireCliSubcommand.test.d.ts +1 -0
- package/umd/src/llm-providers/vercel/VercelExecutionToolsOptions.d.ts +5 -2
- package/umd/src/version.d.ts +1 -1
- package/esm/src/cli/cli-commands/coder/agentCodingFile.d.ts +0 -13
- package/esm/src/cli/cli-commands/common/harnessUpdateCliOptions.d.ts +0 -29
- package/src/cli/cli-commands/coder/agentCodingFile.ts +0 -25
- package/src/cli/cli-commands/common/harnessUpdateCliOptions.ts +0 -46
- package/umd/src/cli/cli-commands/coder/agentCodingFile.d.ts +0 -13
- package/umd/src/cli/cli-commands/common/harnessUpdateCliOptions.d.ts +0 -29
- /package/esm/src/cli/cli-commands/{common/harnessUpdateCliOptions.test.d.ts → coder/init.test.d.ts} +0 -0
- /package/{umd/src/cli/cli-commands/common/harnessUpdateCliOptions.test.d.ts → esm/src/cli/cli-commands/common/$askForConfirmation.test.d.ts} +0 -0
package/esm/index.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import colors from 'colors';
|
|
2
2
|
import commander, { Option } from 'commander';
|
|
3
3
|
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
4
|
-
import { writeFile, stat, mkdir, readFile,
|
|
4
|
+
import { writeFile, stat, readdir, mkdir, readFile, rm, cp, lstat, symlink, rename, unlink, appendFile, realpath, copyFile, statfs, access, constants, watch, rmdir } from 'fs/promises';
|
|
5
5
|
import { join, delimiter, relative, basename, resolve, dirname, isAbsolute, extname } from 'path';
|
|
6
6
|
import { createHash, randomBytes } from 'crypto';
|
|
7
7
|
import { spawn, spawnSync, execFile } from 'child_process';
|
|
@@ -48,7 +48,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
48
48
|
* @generated
|
|
49
49
|
* @see https://github.com/webgptorg/promptbook
|
|
50
50
|
*/
|
|
51
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
51
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-34';
|
|
52
52
|
/**
|
|
53
53
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
54
54
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1708,6 +1708,35 @@ function $initializeAboutCommand(program) {
|
|
|
1708
1708
|
// TODO: [🗽] Unite branding and make single place for it
|
|
1709
1709
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1710
1710
|
|
|
1711
|
+
/**
|
|
1712
|
+
* Message printed when one CLI command which only groups subcommands is run without picking any of them.
|
|
1713
|
+
*
|
|
1714
|
+
* @private internal constant of `$requireCliSubcommand`
|
|
1715
|
+
*/
|
|
1716
|
+
const MISSING_CLI_SUBCOMMAND_MESSAGE = 'Please specify a subcommand.';
|
|
1717
|
+
/**
|
|
1718
|
+
* Makes one CLI command which only groups subcommands ask for a subcommand instead of doing anything on its own.
|
|
1719
|
+
*
|
|
1720
|
+
* Note: `$` is used to indicate that this function is not a pure function - it registers an action in the CLI
|
|
1721
|
+
*
|
|
1722
|
+
* @private utility of CLI
|
|
1723
|
+
*/
|
|
1724
|
+
function $requireCliSubcommand(command) {
|
|
1725
|
+
command.action(() => $reportMissingCliSubcommand(command));
|
|
1726
|
+
}
|
|
1727
|
+
/**
|
|
1728
|
+
* Asks for a subcommand of one CLI command, prints its help and exits the process.
|
|
1729
|
+
*
|
|
1730
|
+
* Note: `$` is used to indicate that this function is not a pure function - it writes to the console and exits the process
|
|
1731
|
+
*
|
|
1732
|
+
* @private utility of CLI
|
|
1733
|
+
*/
|
|
1734
|
+
function $reportMissingCliSubcommand(command) {
|
|
1735
|
+
console.info(colors.yellow(MISSING_CLI_SUBCOMMAND_MESSAGE));
|
|
1736
|
+
console.info('');
|
|
1737
|
+
return command.help();
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1711
1740
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1712
1741
|
/**
|
|
1713
1742
|
* All CLI harness names supported by `CliAgent` and `ptbk agent exec`.
|
|
@@ -2103,11 +2132,7 @@ function $initializeAgentCommand(program) {
|
|
|
2103
2132
|
`));
|
|
2104
2133
|
$initializeAgentChatCommand(agentCommand);
|
|
2105
2134
|
$initializeAgentExecCommand(agentCommand);
|
|
2106
|
-
agentCommand
|
|
2107
|
-
console.info(colors.yellow('Please specify a subcommand.'));
|
|
2108
|
-
console.info('');
|
|
2109
|
-
agentCommand.help();
|
|
2110
|
-
});
|
|
2135
|
+
$requireCliSubcommand(agentCommand);
|
|
2111
2136
|
}
|
|
2112
2137
|
// Note: [🟡] Code for CLI command [agent](src/cli/cli-commands/agent.ts) should never be published outside of `@promptbook/cli`
|
|
2113
2138
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -2265,6 +2290,23 @@ async function ensureDirectory(projectPath, relativeDirectoryPath) {
|
|
|
2265
2290
|
}
|
|
2266
2291
|
return 'unchanged';
|
|
2267
2292
|
}
|
|
2293
|
+
/**
|
|
2294
|
+
* Checks whether a project-relative directory is missing or contains no entries.
|
|
2295
|
+
*
|
|
2296
|
+
* @private internal utility of `coder init` command
|
|
2297
|
+
*/
|
|
2298
|
+
async function isDirectoryEmpty(projectPath, relativeDirectoryPath) {
|
|
2299
|
+
const directoryPath = join(projectPath, relativeDirectoryPath);
|
|
2300
|
+
try {
|
|
2301
|
+
return (await readdir(directoryPath)).length === 0;
|
|
2302
|
+
}
|
|
2303
|
+
catch (error) {
|
|
2304
|
+
if (isNodeJsErrorWithCode$1(error, 'ENOENT')) {
|
|
2305
|
+
return true;
|
|
2306
|
+
}
|
|
2307
|
+
throw error;
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2268
2310
|
/**
|
|
2269
2311
|
* Checks whether a path exists and is a directory.
|
|
2270
2312
|
*/
|
|
@@ -2276,6 +2318,12 @@ async function isExistingDirectory$2(path) {
|
|
|
2276
2318
|
return false;
|
|
2277
2319
|
}
|
|
2278
2320
|
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Checks whether a caught value is a Node.js error with the given error code.
|
|
2323
|
+
*/
|
|
2324
|
+
function isNodeJsErrorWithCode$1(error, code) {
|
|
2325
|
+
return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
|
|
2326
|
+
}
|
|
2279
2327
|
// Note: [🟡] Code for coder init directory creation [ensureDirectory](src/cli/cli-commands/coder/ensureDirectory.ts) should never be published outside of `@promptbook/cli`
|
|
2280
2328
|
|
|
2281
2329
|
/**
|
|
@@ -2563,11 +2611,7 @@ function $initializeAgentFolderCommand(program) {
|
|
|
2563
2611
|
$initializeAgentTickCommand(agentFolderCommand);
|
|
2564
2612
|
$initializeAgentRunCommand(agentFolderCommand);
|
|
2565
2613
|
$initializeAgentRunMultipleCommand(agentFolderCommand);
|
|
2566
|
-
agentFolderCommand
|
|
2567
|
-
console.info(colors.yellow('Please specify a subcommand.'));
|
|
2568
|
-
console.info('');
|
|
2569
|
-
agentFolderCommand.help();
|
|
2570
|
-
});
|
|
2614
|
+
$requireCliSubcommand(agentFolderCommand);
|
|
2571
2615
|
}
|
|
2572
2616
|
// Note: [🟡] Code for CLI command [agent-folder](src/cli/cli-commands/agent-folder.ts) should never be published outside of `@promptbook/cli`
|
|
2573
2617
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -21418,10 +21462,30 @@ function normalizeRelativePath$3(relativePath) {
|
|
|
21418
21462
|
return relativePath.replace(/\\/gu, '/');
|
|
21419
21463
|
}
|
|
21420
21464
|
|
|
21465
|
+
/**
|
|
21466
|
+
* AuthenticationError is thrown from login function which is dependency of remote server
|
|
21467
|
+
*
|
|
21468
|
+
* @public exported from `@promptbook/core`
|
|
21469
|
+
*/
|
|
21470
|
+
class AuthenticationError extends Error {
|
|
21471
|
+
constructor(message) {
|
|
21472
|
+
super(message);
|
|
21473
|
+
this.name = 'AuthenticationError';
|
|
21474
|
+
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
21475
|
+
}
|
|
21476
|
+
}
|
|
21477
|
+
|
|
21421
21478
|
/**
|
|
21422
21479
|
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
21480
|
+
*
|
|
21481
|
+
* An `AuthenticationError` is reported without its stack, because its message is written for the user - it
|
|
21482
|
+
* says which harness has to be signed in again and how - and the frames of a failure nobody can debug would
|
|
21483
|
+
* only push those instructions out of sight.
|
|
21423
21484
|
*/
|
|
21424
21485
|
function formatUnknownErrorDetails(error) {
|
|
21486
|
+
if (error instanceof AuthenticationError) {
|
|
21487
|
+
return error.message;
|
|
21488
|
+
}
|
|
21425
21489
|
if (error instanceof Error) {
|
|
21426
21490
|
return error.stack || error.message;
|
|
21427
21491
|
}
|
|
@@ -24138,6 +24202,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24138
24202
|
commandName: 'codex',
|
|
24139
24203
|
npmPackageName: '@openai/codex',
|
|
24140
24204
|
projectGitignoreRules: ['.codex'],
|
|
24205
|
+
authenticationMethod: { command: 'codex login' },
|
|
24141
24206
|
// Note: The official standalone installer keeps its package in `~/.codex` and links it onto the `PATH`
|
|
24142
24207
|
standaloneInstallation: {
|
|
24143
24208
|
directoryNames: ['.codex'],
|
|
@@ -24150,6 +24215,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24150
24215
|
commandName: 'copilot',
|
|
24151
24216
|
npmPackageName: '@github/copilot',
|
|
24152
24217
|
projectGitignoreRules: ['.github/copilot/settings.local.json'],
|
|
24218
|
+
authenticationMethod: { command: 'copilot', interactiveStep: 'running the `/login` command inside it' },
|
|
24153
24219
|
// Note: The GitHub Copilot CLI downloads its native binary in a postinstall script
|
|
24154
24220
|
npmInstallEnvironment: { npm_config_ignore_scripts: 'false' },
|
|
24155
24221
|
},
|
|
@@ -24159,6 +24225,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24159
24225
|
commandName: 'cline',
|
|
24160
24226
|
npmPackageName: 'cline',
|
|
24161
24227
|
projectGitignoreRules: ['.cline'],
|
|
24228
|
+
authenticationMethod: { command: 'cline', interactiveStep: 'signing in to the provider inside it' },
|
|
24162
24229
|
},
|
|
24163
24230
|
'claude-code': {
|
|
24164
24231
|
harnessName: 'claude-code',
|
|
@@ -24166,6 +24233,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24166
24233
|
commandName: 'claude',
|
|
24167
24234
|
npmPackageName: '@anthropic-ai/claude-code',
|
|
24168
24235
|
projectGitignoreRules: ['.claude'],
|
|
24236
|
+
authenticationMethod: { command: 'claude', interactiveStep: 'running the `/login` command inside it' },
|
|
24169
24237
|
},
|
|
24170
24238
|
opencode: {
|
|
24171
24239
|
harnessName: 'opencode',
|
|
@@ -24173,6 +24241,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24173
24241
|
commandName: 'opencode',
|
|
24174
24242
|
npmPackageName: 'opencode-ai',
|
|
24175
24243
|
projectGitignoreRules: ['.opencode'],
|
|
24244
|
+
authenticationMethod: { command: 'opencode auth login' },
|
|
24176
24245
|
},
|
|
24177
24246
|
gemini: {
|
|
24178
24247
|
harnessName: 'gemini',
|
|
@@ -24180,6 +24249,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24180
24249
|
commandName: 'gemini',
|
|
24181
24250
|
npmPackageName: '@google/gemini-cli',
|
|
24182
24251
|
projectGitignoreRules: ['.gemini'],
|
|
24252
|
+
authenticationMethod: { command: 'gemini', interactiveStep: 'running the `/auth` command inside it' },
|
|
24183
24253
|
},
|
|
24184
24254
|
'qwen-code': {
|
|
24185
24255
|
harnessName: 'qwen-code',
|
|
@@ -24187,6 +24257,7 @@ const HARNESS_DEFINITIONS = {
|
|
|
24187
24257
|
commandName: 'qwen',
|
|
24188
24258
|
npmPackageName: '@qwen-code/qwen-code',
|
|
24189
24259
|
projectGitignoreRules: ['.qwen'],
|
|
24260
|
+
authenticationMethod: { command: 'qwen', interactiveStep: 'running the `/auth` command inside it' },
|
|
24190
24261
|
},
|
|
24191
24262
|
};
|
|
24192
24263
|
/**
|
|
@@ -26220,6 +26291,183 @@ function formatClaudeCodeSessionIdForDisplay(sessionId) {
|
|
|
26220
26291
|
return `${sessionId.slice(0, 8)}...`;
|
|
26221
26292
|
}
|
|
26222
26293
|
|
|
26294
|
+
/**
|
|
26295
|
+
* Formats one unknown error-like value into its readable message without the stack trace.
|
|
26296
|
+
*
|
|
26297
|
+
* Use this instead of `formatUnknownErrorDetails` whenever the text is shown to the user, for example
|
|
26298
|
+
* inside a branded error, where the stack of the wrapped error would only bury the actual cause.
|
|
26299
|
+
*/
|
|
26300
|
+
function formatUnknownErrorMessage(error) {
|
|
26301
|
+
if (error instanceof Error) {
|
|
26302
|
+
return error.message;
|
|
26303
|
+
}
|
|
26304
|
+
if (typeof error === 'string') {
|
|
26305
|
+
return error;
|
|
26306
|
+
}
|
|
26307
|
+
const serializedError = JSON.stringify(error, null, 2);
|
|
26308
|
+
return serializedError !== null && serializedError !== void 0 ? serializedError : String(error);
|
|
26309
|
+
}
|
|
26310
|
+
|
|
26311
|
+
/**
|
|
26312
|
+
* Builds the branded error which tells the user that the selected harness has to be signed in again.
|
|
26313
|
+
*/
|
|
26314
|
+
function buildHarnessAuthenticationError(options) {
|
|
26315
|
+
const { harnessName, reason } = options;
|
|
26316
|
+
const { label, authenticationMethod } = getHarnessDefinition(harnessName);
|
|
26317
|
+
return new AuthenticationError(spaceTrim((block) => `
|
|
26318
|
+
The **${label}** harness is not authenticated, so the prompt was not run.
|
|
26319
|
+
|
|
26320
|
+
${label} reported:
|
|
26321
|
+
> ${reason}
|
|
26322
|
+
|
|
26323
|
+
${block(buildSignInInstruction(authenticationMethod))}
|
|
26324
|
+
|
|
26325
|
+
Once you are signed in, start the very same \`ptbk coder\` command again.
|
|
26326
|
+
`));
|
|
26327
|
+
}
|
|
26328
|
+
/**
|
|
26329
|
+
* Builds the sentence which tells the user how to sign in to one harness again.
|
|
26330
|
+
*/
|
|
26331
|
+
function buildSignInInstruction(authenticationMethod) {
|
|
26332
|
+
const { command, interactiveStep } = authenticationMethod;
|
|
26333
|
+
if (interactiveStep === undefined) {
|
|
26334
|
+
return `Sign in again by running \`${command}\`.`;
|
|
26335
|
+
}
|
|
26336
|
+
return `Sign in again by running \`${command}\` and then ${interactiveStep}.`;
|
|
26337
|
+
}
|
|
26338
|
+
|
|
26339
|
+
/**
|
|
26340
|
+
* Maximum length of the harness reason quoted back to the user.
|
|
26341
|
+
*/
|
|
26342
|
+
const MAXIMUM_AUTHENTICATION_FAILURE_REASON_LENGTH = 300;
|
|
26343
|
+
/**
|
|
26344
|
+
* Keys of machine-readable harness output whose string value carries the human-readable failure reason.
|
|
26345
|
+
*
|
|
26346
|
+
* Harnesses which stream JSON events - like Claude Code with its `stream-json` output - report the reason only
|
|
26347
|
+
* inside such a value, surrounded by hundreds of characters of session metadata which must never be shown to
|
|
26348
|
+
* the user. The keys are ordered from the most to the least conclusive one.
|
|
26349
|
+
*/
|
|
26350
|
+
const HARNESS_FAILURE_MESSAGE_KEYS = ['result', 'error_message', 'message', 'text'];
|
|
26351
|
+
/**
|
|
26352
|
+
* Patterns which extract one JSON string value reported under a harness failure message key.
|
|
26353
|
+
*/
|
|
26354
|
+
const HARNESS_FAILURE_MESSAGE_PATTERNS = HARNESS_FAILURE_MESSAGE_KEYS.map((messageKey) => new RegExp(`"${messageKey}"\\s*:\\s*("(?:[^"\\\\]|\\\\.)*")`, 'g'));
|
|
26355
|
+
/**
|
|
26356
|
+
* Signatures which mean that the harness refused to work because it is not logged in.
|
|
26357
|
+
*
|
|
26358
|
+
* They are deliberately narrow phrases instead of single words like `login`, because the output of a harness
|
|
26359
|
+
* routinely mentions its own `/login` command among the commands it offers, and such a mention must never be
|
|
26360
|
+
* read as a failed login.
|
|
26361
|
+
*/
|
|
26362
|
+
const AUTHENTICATION_FAILURE_PATTERNS = [
|
|
26363
|
+
/\bauthentication[ _-]?failed\b/i,
|
|
26364
|
+
/\bfailed to authenticate\b/i,
|
|
26365
|
+
/\bnot authenticated\b/i,
|
|
26366
|
+
/\bnot logged[ -]?in\b/i,
|
|
26367
|
+
/\bnot signed[ -]?in\b/i,
|
|
26368
|
+
/\bno authentication information found\b/i,
|
|
26369
|
+
/\bauthentication (?:is )?required\b/i,
|
|
26370
|
+
/\blogin (?:is )?required\b/i,
|
|
26371
|
+
/\bplease (?:log|sign) in\b/i,
|
|
26372
|
+
/\bunauthorized\b/i,
|
|
26373
|
+
/\b(?:oauth|session|token|credentials?|login)\b[^.]{0,60}?\bexpired\b/i,
|
|
26374
|
+
/\bexpired\b[^.]{0,60}?\b(?:oauth|session|token|credentials?|login)\b/i,
|
|
26375
|
+
/\binvalid api[ _-]?key\b/i,
|
|
26376
|
+
/\bmissing api[ _-]?key\b/i,
|
|
26377
|
+
/\binvalid credentials?\b/i,
|
|
26378
|
+
];
|
|
26379
|
+
/**
|
|
26380
|
+
* Reads the reason why a harness refused to work because it is not logged in, from its raw CLI output.
|
|
26381
|
+
*
|
|
26382
|
+
* Messages the harness reports in machine-readable output are preferred over its raw output lines, so the
|
|
26383
|
+
* reason is the sentence the harness wrote for a human and not the JSON event which transported it.
|
|
26384
|
+
*
|
|
26385
|
+
* @returns One short single-line reason, or `undefined` when the failure was not caused by authentication.
|
|
26386
|
+
*/
|
|
26387
|
+
function extractHarnessAuthenticationFailureReason(harnessOutput) {
|
|
26388
|
+
const reportedMessages = [...extractHarnessReportedMessages(harnessOutput), ...harnessOutput.split(/\r?\n/)];
|
|
26389
|
+
for (const reportedMessage of reportedMessages) {
|
|
26390
|
+
const reason = reportedMessage.replace(/\s+/g, ' ').trim();
|
|
26391
|
+
if (isAuthenticationFailureReason(reason)) {
|
|
26392
|
+
return limitAuthenticationFailureReason(reason);
|
|
26393
|
+
}
|
|
26394
|
+
}
|
|
26395
|
+
return undefined;
|
|
26396
|
+
}
|
|
26397
|
+
/**
|
|
26398
|
+
* Lists the human-readable messages a harness reported in its machine-readable output.
|
|
26399
|
+
*/
|
|
26400
|
+
function extractHarnessReportedMessages(harnessOutput) {
|
|
26401
|
+
const reportedMessages = [];
|
|
26402
|
+
for (const messagePattern of HARNESS_FAILURE_MESSAGE_PATTERNS) {
|
|
26403
|
+
for (const match of harnessOutput.matchAll(messagePattern)) {
|
|
26404
|
+
const reportedMessage = parseSerializedJsonString(match[1]);
|
|
26405
|
+
if (reportedMessage !== undefined) {
|
|
26406
|
+
reportedMessages.push(reportedMessage);
|
|
26407
|
+
}
|
|
26408
|
+
}
|
|
26409
|
+
}
|
|
26410
|
+
return reportedMessages;
|
|
26411
|
+
}
|
|
26412
|
+
/**
|
|
26413
|
+
* Reads one JSON string literal back into plain text, tolerating output which only looks like JSON.
|
|
26414
|
+
*/
|
|
26415
|
+
function parseSerializedJsonString(serializedString) {
|
|
26416
|
+
if (serializedString === undefined) {
|
|
26417
|
+
return undefined;
|
|
26418
|
+
}
|
|
26419
|
+
try {
|
|
26420
|
+
const parsedString = JSON.parse(serializedString);
|
|
26421
|
+
return typeof parsedString === 'string' ? parsedString : undefined;
|
|
26422
|
+
}
|
|
26423
|
+
catch (_a) {
|
|
26424
|
+
return undefined;
|
|
26425
|
+
}
|
|
26426
|
+
}
|
|
26427
|
+
/**
|
|
26428
|
+
* Returns true when one message of the harness says that it is not logged in.
|
|
26429
|
+
*/
|
|
26430
|
+
function isAuthenticationFailureReason(reportedMessage) {
|
|
26431
|
+
return AUTHENTICATION_FAILURE_PATTERNS.some((pattern) => pattern.test(reportedMessage));
|
|
26432
|
+
}
|
|
26433
|
+
/**
|
|
26434
|
+
* Shortens a very long reason, so the guidance which follows it stays visible in the terminal.
|
|
26435
|
+
*/
|
|
26436
|
+
function limitAuthenticationFailureReason(reason) {
|
|
26437
|
+
if (reason.length <= MAXIMUM_AUTHENTICATION_FAILURE_REASON_LENGTH) {
|
|
26438
|
+
return reason;
|
|
26439
|
+
}
|
|
26440
|
+
return `${reason.slice(0, MAXIMUM_AUTHENTICATION_FAILURE_REASON_LENGTH)}...`;
|
|
26441
|
+
}
|
|
26442
|
+
|
|
26443
|
+
/**
|
|
26444
|
+
* Wraps one prompt runner so a failure caused by a missing or expired harness login is reported as a branded
|
|
26445
|
+
* `AuthenticationError` which tells the user how to sign in again.
|
|
26446
|
+
*
|
|
26447
|
+
* Each harness reports its own failures differently, but all of them report them by failing `runPrompt` with
|
|
26448
|
+
* the raw CLI output as the message. Translating the failure here therefore keeps exactly one place which has
|
|
26449
|
+
* to recognize an unauthenticated harness, for every harness and for every command which runs prompts.
|
|
26450
|
+
*/
|
|
26451
|
+
function createAuthenticationAwarePromptRunner(runner, harnessName) {
|
|
26452
|
+
var _a;
|
|
26453
|
+
return {
|
|
26454
|
+
name: runner.name,
|
|
26455
|
+
runPrompt: async (options) => {
|
|
26456
|
+
try {
|
|
26457
|
+
return await runner.runPrompt(options);
|
|
26458
|
+
}
|
|
26459
|
+
catch (error) {
|
|
26460
|
+
const reason = extractHarnessAuthenticationFailureReason(formatUnknownErrorMessage(error));
|
|
26461
|
+
if (reason === undefined) {
|
|
26462
|
+
throw error;
|
|
26463
|
+
}
|
|
26464
|
+
throw buildHarnessAuthenticationError({ harnessName, reason });
|
|
26465
|
+
}
|
|
26466
|
+
},
|
|
26467
|
+
getSubscriptionUsage: (_a = runner.getSubscriptionUsage) === null || _a === void 0 ? void 0 : _a.bind(runner),
|
|
26468
|
+
};
|
|
26469
|
+
}
|
|
26470
|
+
|
|
26223
26471
|
/**
|
|
26224
26472
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
26225
26473
|
*/
|
|
@@ -27959,6 +28207,18 @@ function resolvePromptRunner(options) {
|
|
|
27959
28207
|
if (!agentName) {
|
|
27960
28208
|
throw new Error('Missing --harness in non-dry run mode');
|
|
27961
28209
|
}
|
|
28210
|
+
const resolution = resolveHarnessPromptRunner(agentName, options);
|
|
28211
|
+
return {
|
|
28212
|
+
...resolution,
|
|
28213
|
+
// Note: Every harness is wrapped here, so a harness which is not logged in is reported the same clear
|
|
28214
|
+
// way no matter which harness it is and which command has resolved the runner
|
|
28215
|
+
runner: createAuthenticationAwarePromptRunner(resolution.runner, agentName),
|
|
28216
|
+
};
|
|
28217
|
+
}
|
|
28218
|
+
/**
|
|
28219
|
+
* Creates the runner of one selected harness together with its status-line metadata.
|
|
28220
|
+
*/
|
|
28221
|
+
function resolveHarnessPromptRunner(agentName, options) {
|
|
27962
28222
|
if (agentName === 'openai-codex') {
|
|
27963
28223
|
return createOpenAiCodexRunnerResolution(options);
|
|
27964
28224
|
}
|
|
@@ -28426,11 +28686,19 @@ const MIN_FRAME_WIDTH = 56;
|
|
|
28426
28686
|
* Maximum width used for the rich coder-run frame.
|
|
28427
28687
|
*/
|
|
28428
28688
|
const MAX_FRAME_WIDTH = 96;
|
|
28689
|
+
/**
|
|
28690
|
+
* Number of terminal columns deliberately left unused by the rich coder-run frame.
|
|
28691
|
+
*
|
|
28692
|
+
* A row which fills the final physical terminal column can auto-wrap. The incremental terminal
|
|
28693
|
+
* updater moves by logical rows, so an auto-wrapped row would put its cursor out of sync with the
|
|
28694
|
+
* frame and let a later animated avatar redraw overwrite dashboard content.
|
|
28695
|
+
*/
|
|
28696
|
+
const TERMINAL_AUTO_WRAP_RESERVED_COLUMNS = 1;
|
|
28429
28697
|
/**
|
|
28430
28698
|
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
28431
28699
|
*/
|
|
28432
28700
|
function buildCoderRunUiFrame(options) {
|
|
28433
|
-
const totalWidth =
|
|
28701
|
+
const totalWidth = resolveCoderRunUiFrameWidth(options.terminalWidth);
|
|
28434
28702
|
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
28435
28703
|
const promptStatusPrefix = isPromptActive ? `${colors.yellow(`${options.spinner} `)}` : '';
|
|
28436
28704
|
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.pauseTargetLabel, options.statusMessage);
|
|
@@ -28467,6 +28735,16 @@ function buildCoderRunUiFrame(options) {
|
|
|
28467
28735
|
frame.push(...renderBox('Controls', controlsBoxLines, totalWidth, colors.white.bold));
|
|
28468
28736
|
return frame;
|
|
28469
28737
|
}
|
|
28738
|
+
/**
|
|
28739
|
+
* Resolves the safe width of the rich terminal frame from the available physical terminal columns.
|
|
28740
|
+
*
|
|
28741
|
+
* The reserved trailing column keeps every boxed row from auto-wrapping, which makes the frame's
|
|
28742
|
+
* logical row count match its physical terminal row count during animated incremental redraws.
|
|
28743
|
+
*/
|
|
28744
|
+
function resolveCoderRunUiFrameWidth(terminalWidth) {
|
|
28745
|
+
const availableFrameWidth = terminalWidth - TERMINAL_AUTO_WRAP_RESERVED_COLUMNS;
|
|
28746
|
+
return Math.max(MIN_FRAME_WIDTH, Math.min(availableFrameWidth, MAX_FRAME_WIDTH));
|
|
28747
|
+
}
|
|
28470
28748
|
/**
|
|
28471
28749
|
* Builds the header visual above the dashboard boxes.
|
|
28472
28750
|
*
|
|
@@ -29943,16 +30221,14 @@ const SPINNER_FRAMES = [
|
|
|
29943
30221
|
*/
|
|
29944
30222
|
const DEFAULT_TERMINAL_WIDTH = 80;
|
|
29945
30223
|
/**
|
|
29946
|
-
*
|
|
29947
|
-
|
|
29948
|
-
|
|
29949
|
-
/**
|
|
29950
|
-
* Returns the usable terminal width, capped at 96.
|
|
30224
|
+
* Returns the number of columns reported by the current terminal.
|
|
30225
|
+
*
|
|
30226
|
+
* The frame builder owns clamping and reserves its trailing auto-wrap safety column.
|
|
29951
30227
|
*
|
|
29952
30228
|
* @private internal utility of coder run UI
|
|
29953
30229
|
*/
|
|
29954
|
-
function
|
|
29955
|
-
return
|
|
30230
|
+
function getTerminalColumnCount() {
|
|
30231
|
+
return process.stdout.columns || DEFAULT_TERMINAL_WIDTH;
|
|
29956
30232
|
}
|
|
29957
30233
|
/**
|
|
29958
30234
|
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
@@ -30059,7 +30335,7 @@ function renderCoderRunUi(startTime, options = {}) {
|
|
|
30059
30335
|
*/
|
|
30060
30336
|
function buildFrameLines() {
|
|
30061
30337
|
return buildFrameLinesFromState({
|
|
30062
|
-
terminalWidth:
|
|
30338
|
+
terminalWidth: getTerminalColumnCount(),
|
|
30063
30339
|
animationFrame: spinnerFrame,
|
|
30064
30340
|
animationTimeMs: Date.now() - animationStartTimeMs,
|
|
30065
30341
|
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
@@ -33790,19 +34066,6 @@ class CsvFormatError extends AbstractFormatError {
|
|
|
33790
34066
|
}
|
|
33791
34067
|
}
|
|
33792
34068
|
|
|
33793
|
-
/**
|
|
33794
|
-
* AuthenticationError is thrown from login function which is dependency of remote server
|
|
33795
|
-
*
|
|
33796
|
-
* @public exported from `@promptbook/core`
|
|
33797
|
-
*/
|
|
33798
|
-
class AuthenticationError extends Error {
|
|
33799
|
-
constructor(message) {
|
|
33800
|
-
super(message);
|
|
33801
|
-
this.name = 'AuthenticationError';
|
|
33802
|
-
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
33803
|
-
}
|
|
33804
|
-
}
|
|
33805
|
-
|
|
33806
34069
|
/**
|
|
33807
34070
|
* This error indicates that the pipeline collection cannot be properly loaded
|
|
33808
34071
|
*
|
|
@@ -42031,11 +42294,7 @@ function $initializeAgentsServerCommand(program) {
|
|
|
42031
42294
|
$initializeAgentsServerDevCommand(agentsServerCommand);
|
|
42032
42295
|
$initializeAgentsServerInitCommand(agentsServerCommand);
|
|
42033
42296
|
$initializeAgentsServerStartCommand(agentsServerCommand);
|
|
42034
|
-
agentsServerCommand
|
|
42035
|
-
console.info(colors.yellow('Please specify a subcommand.'));
|
|
42036
|
-
console.info('');
|
|
42037
|
-
agentsServerCommand.help();
|
|
42038
|
-
});
|
|
42297
|
+
$requireCliSubcommand(agentsServerCommand);
|
|
42039
42298
|
}
|
|
42040
42299
|
// Note: [🟡] Code for CLI command [agents-server](src/cli/cli-commands/agents-server.ts) should never be published outside of `@promptbook/cli`
|
|
42041
42300
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -42125,6 +42384,58 @@ function normalizeCoderGitSyncCliOptions(cliOptions) {
|
|
|
42125
42384
|
// Note: [🟡] Code for CLI git synchronization options [coderGitSyncCliOptions](src/cli/cli-commands/common/coderGitSyncCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
42126
42385
|
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
42127
42386
|
|
|
42387
|
+
/**
|
|
42388
|
+
* Description block shared by the `ptbk coder` commands which can ask interactive questions.
|
|
42389
|
+
*
|
|
42390
|
+
* @private internal utility of `promptbookCli`
|
|
42391
|
+
*/
|
|
42392
|
+
const QUESTIONS_DESCRIPTION = spaceTrim$1(`
|
|
42393
|
+
Interactive questions:
|
|
42394
|
+
- Steps which need an answer to continue are asked in the terminal
|
|
42395
|
+
- --no-questions never asks: an optional step is skipped with a note how to do it manually, a required one fails right away
|
|
42396
|
+
`);
|
|
42397
|
+
/**
|
|
42398
|
+
* Registers the shared `--no-questions` option on a `ptbk coder` command which can ask interactive questions.
|
|
42399
|
+
*
|
|
42400
|
+
* @private internal utility of `promptbookCli`
|
|
42401
|
+
*/
|
|
42402
|
+
function addQuestionsOption(command) {
|
|
42403
|
+
command.option('--no-questions', 'Never ask an interactive question and skip every optional step which needs an answer to continue');
|
|
42404
|
+
}
|
|
42405
|
+
/**
|
|
42406
|
+
* Converts the Commander questions flag into the normalized interactive-questions option.
|
|
42407
|
+
*
|
|
42408
|
+
* @private internal utility of `promptbookCli`
|
|
42409
|
+
*/
|
|
42410
|
+
function normalizeQuestionsCliOptions(cliOptions) {
|
|
42411
|
+
return {
|
|
42412
|
+
isAskingQuestionsEnabled: cliOptions.questions,
|
|
42413
|
+
};
|
|
42414
|
+
}
|
|
42415
|
+
/**
|
|
42416
|
+
* Asserts that a command which waits for a user confirmation before each prompt is allowed to ask for it.
|
|
42417
|
+
*
|
|
42418
|
+
* @throws {NotAllowed} when `--no-auto` is combined with `--no-questions`
|
|
42419
|
+
* @private internal utility of `promptbookCli`
|
|
42420
|
+
*/
|
|
42421
|
+
function assertUserConfirmationIsAllowed(options) {
|
|
42422
|
+
const { isAskingQuestionsEnabled, isWaitingForUser } = options;
|
|
42423
|
+
if (!isWaitingForUser || isAskingQuestionsEnabled) {
|
|
42424
|
+
return;
|
|
42425
|
+
}
|
|
42426
|
+
throw new NotAllowed(spaceTrim$1(`
|
|
42427
|
+
Flag \`--no-auto\` can not be used together with \`--no-questions\`.
|
|
42428
|
+
|
|
42429
|
+
**There is nobody who could confirm each prompt when no question may be asked.**
|
|
42430
|
+
|
|
42431
|
+
Actionable hints:
|
|
42432
|
+
- Keep \`--no-auto\` for a supervised run, for example \`ptbk coder run --harness claude-code --no-auto\`.
|
|
42433
|
+
- Keep \`--no-questions\` for an unattended run, for example \`ptbk coder run --harness claude-code --no-questions\`.
|
|
42434
|
+
`));
|
|
42435
|
+
}
|
|
42436
|
+
// Note: [🟡] Code for CLI interactive questions options [questionsCliOptions](src/cli/cli-commands/common/questionsCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
42437
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
42438
|
+
|
|
42128
42439
|
/**
|
|
42129
42440
|
* Relative path to the root prompts directory used by Promptbook coder utilities.
|
|
42130
42441
|
*
|
|
@@ -42143,6 +42454,12 @@ const PROMPTS_DONE_DIRECTORY_PATH = join(PROMPTS_DIRECTORY_PATH$1, 'done');
|
|
|
42143
42454
|
* @private internal utility of `ptbk coder`
|
|
42144
42455
|
*/
|
|
42145
42456
|
const PROMPTS_TEMPLATES_DIRECTORY_PATH = join(PROMPTS_DIRECTORY_PATH$1, 'templates');
|
|
42457
|
+
/**
|
|
42458
|
+
* Relative path to the project-agnostic `common` boilerplate template referenced by the default coder scripts.
|
|
42459
|
+
*
|
|
42460
|
+
* @private internal utility of `ptbk coder`
|
|
42461
|
+
*/
|
|
42462
|
+
const COMMON_PROMPT_TEMPLATE_FILE_PATH = join(PROMPTS_TEMPLATES_DIRECTORY_PATH, 'common.md');
|
|
42146
42463
|
/**
|
|
42147
42464
|
* Built-in boilerplate templates available to `coder generate-boilerplates`.
|
|
42148
42465
|
*
|
|
@@ -42151,7 +42468,7 @@ const PROMPTS_TEMPLATES_DIRECTORY_PATH = join(PROMPTS_DIRECTORY_PATH$1, 'templat
|
|
|
42151
42468
|
const DEFAULT_CODER_PROMPT_TEMPLATE_DEFINITIONS = [
|
|
42152
42469
|
{
|
|
42153
42470
|
id: 'common',
|
|
42154
|
-
relativeFilePath:
|
|
42471
|
+
relativeFilePath: COMMON_PROMPT_TEMPLATE_FILE_PATH,
|
|
42155
42472
|
slugPrefix: null,
|
|
42156
42473
|
content: spaceTrim$1(`
|
|
42157
42474
|
- @@@
|
|
@@ -42197,30 +42514,17 @@ function getDefaultCoderPromptTemplateDefinition(template) {
|
|
|
42197
42514
|
return definition;
|
|
42198
42515
|
}
|
|
42199
42516
|
/**
|
|
42200
|
-
* Ensures
|
|
42517
|
+
* Ensures one project-owned coder template file exists without overwriting user customizations.
|
|
42201
42518
|
*
|
|
42202
42519
|
* @private internal utility of `ptbk coder`
|
|
42203
42520
|
*/
|
|
42204
|
-
async function
|
|
42205
|
-
const
|
|
42206
|
-
|
|
42207
|
-
|
|
42208
|
-
if (await isExistingFile$3(absoluteTemplatePath)) {
|
|
42209
|
-
ensuredTemplateFiles.push({
|
|
42210
|
-
id: definition.id,
|
|
42211
|
-
relativeFilePath: definition.relativeFilePath,
|
|
42212
|
-
status: 'unchanged',
|
|
42213
|
-
});
|
|
42214
|
-
continue;
|
|
42215
|
-
}
|
|
42216
|
-
await writeFile(absoluteTemplatePath, `${definition.content}\n`, 'utf-8');
|
|
42217
|
-
ensuredTemplateFiles.push({
|
|
42218
|
-
id: definition.id,
|
|
42219
|
-
relativeFilePath: definition.relativeFilePath,
|
|
42220
|
-
status: 'created',
|
|
42221
|
-
});
|
|
42521
|
+
async function ensureDefaultCoderPromptTemplateFile(projectPath, definition) {
|
|
42522
|
+
const absoluteTemplatePath = join(projectPath, definition.relativeFilePath);
|
|
42523
|
+
if (await isExistingFile$3(absoluteTemplatePath)) {
|
|
42524
|
+
return 'unchanged';
|
|
42222
42525
|
}
|
|
42223
|
-
|
|
42526
|
+
await writeFile(absoluteTemplatePath, `${definition.content}\n`, 'utf-8');
|
|
42527
|
+
return 'created';
|
|
42224
42528
|
}
|
|
42225
42529
|
/**
|
|
42226
42530
|
* Resolves the template requested by `coder generate-boilerplates`.
|
|
@@ -42376,6 +42680,8 @@ function $initializeCoderAddCommand(program) {
|
|
|
42376
42680
|
- \`ptbk coder add\`
|
|
42377
42681
|
|
|
42378
42682
|
${block(CODER_GIT_SYNC_DESCRIPTION)}
|
|
42683
|
+
|
|
42684
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
42379
42685
|
`));
|
|
42380
42686
|
command.argument('[description]', 'Plain-language description of the feature or task to implement');
|
|
42381
42687
|
command.option('--priority <priority>', 'Priority of the new prompt — higher priorities run first (rendered as trailing `!` markers)', parsePriorityOption, 0);
|
|
@@ -42387,11 +42693,13 @@ function $initializeCoderAddCommand(program) {
|
|
|
42387
42693
|
.join(', ')}) or a markdown file path relative to the current project root.
|
|
42388
42694
|
`));
|
|
42389
42695
|
addCoderGitSyncOptions(command);
|
|
42696
|
+
addQuestionsOption(command);
|
|
42390
42697
|
command.action(handleActionErrors(async (descriptionArgument, cliOptions) => {
|
|
42391
42698
|
const { priority, template: templateOption } = cliOptions;
|
|
42392
42699
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
42700
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
42393
42701
|
const projectPath = process.cwd();
|
|
42394
|
-
const description = await resolveCoderPromptDescription(descriptionArgument);
|
|
42702
|
+
const description = await resolveCoderPromptDescription(descriptionArgument, questionsOptions);
|
|
42395
42703
|
// Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
|
|
42396
42704
|
const { $commitCoderChanges, $startCoderGitSync } = await Promise.resolve().then(function () { return coderGitSync; });
|
|
42397
42705
|
const commitScope = await $startCoderGitSync({ gitSync, projectPath });
|
|
@@ -42461,7 +42769,7 @@ async function addCoderPrompt({ projectPath, description, priority, templateOpti
|
|
|
42461
42769
|
*
|
|
42462
42770
|
* @private internal utility of `coder add` command
|
|
42463
42771
|
*/
|
|
42464
|
-
async function resolveCoderPromptDescription(descriptionArgument) {
|
|
42772
|
+
async function resolveCoderPromptDescription(descriptionArgument, { isAskingQuestionsEnabled }) {
|
|
42465
42773
|
if (descriptionArgument !== undefined && descriptionArgument.trim() !== '') {
|
|
42466
42774
|
return descriptionArgument.trim();
|
|
42467
42775
|
}
|
|
@@ -42479,6 +42787,14 @@ async function resolveCoderPromptDescription(descriptionArgument) {
|
|
|
42479
42787
|
}
|
|
42480
42788
|
return standardInputDescription;
|
|
42481
42789
|
}
|
|
42790
|
+
if (!isAskingQuestionsEnabled) {
|
|
42791
|
+
throw new ParseError(spaceTrim$1(`
|
|
42792
|
+
Cannot add a prompt without a description.
|
|
42793
|
+
|
|
42794
|
+
The description can not be typed interactively because \`--no-questions\` is used — provide it as an argument or pipe it through stdin instead:
|
|
42795
|
+
- \`ptbk coder add --no-questions "some new feature"\`
|
|
42796
|
+
`));
|
|
42797
|
+
}
|
|
42482
42798
|
const { default: prompts } = await loadPromptsModule();
|
|
42483
42799
|
const response = await prompts({
|
|
42484
42800
|
type: 'text',
|
|
@@ -43129,10 +43445,15 @@ function buildPromptSlug$1(templateSlugPrefix, title) {
|
|
|
43129
43445
|
*
|
|
43130
43446
|
* Note: `$` is used to indicate that this function is not a pure function - it reads the answer from stdin.
|
|
43131
43447
|
*
|
|
43132
|
-
* @returns `true` when the user confirms, `false` when the user declines
|
|
43448
|
+
* @returns `true` when the user confirms, `false` when the user declines, the terminal is not interactive
|
|
43449
|
+
* or the questions are disabled by `--no-questions`.
|
|
43133
43450
|
* @private internal utility of `promptbookCli`
|
|
43134
43451
|
*/
|
|
43135
|
-
async function $askForConfirmation(question) {
|
|
43452
|
+
async function $askForConfirmation(question, { isAskingQuestionsEnabled }) {
|
|
43453
|
+
if (!isAskingQuestionsEnabled) {
|
|
43454
|
+
// Note: `--no-questions` forbids asking, so the optional change is declined without blocking the run.
|
|
43455
|
+
return false;
|
|
43456
|
+
}
|
|
43136
43457
|
if (!process.stdin.isTTY) {
|
|
43137
43458
|
// Note: In non-interactive environments like CI there is nobody who could confirm the change.
|
|
43138
43459
|
return false;
|
|
@@ -43155,11 +43476,12 @@ async function $askForConfirmation(question) {
|
|
|
43155
43476
|
*
|
|
43156
43477
|
* Note: `$` is used to indicate that this function is not a pure function - it reads the answer from stdin
|
|
43157
43478
|
*
|
|
43158
|
-
* @returns `true` when the user confirms, `false` when the user declines
|
|
43479
|
+
* @returns `true` when the user confirms, `false` when the user declines, the terminal is not interactive
|
|
43480
|
+
* or the questions are disabled by `--no-questions`
|
|
43159
43481
|
* @private internal utility of `promptbookCli`
|
|
43160
43482
|
*/
|
|
43161
|
-
async function $askForNpmPackageInstallationApproval(question) {
|
|
43162
|
-
return $askForConfirmation(question);
|
|
43483
|
+
async function $askForNpmPackageInstallationApproval(question, questionsOptions) {
|
|
43484
|
+
return $askForConfirmation(question, questionsOptions);
|
|
43163
43485
|
}
|
|
43164
43486
|
// Note: [🟡] Code for CLI npm package installation approval [$askForNpmPackageInstallationApproval](src/cli/cli-commands/common/npm/$askForNpmPackageInstallationApproval.ts) should never be published outside of `@promptbook/cli`
|
|
43165
43487
|
|
|
@@ -43349,7 +43671,7 @@ function resolveHarnessUpdatePlan(definition, installationMethod) {
|
|
|
43349
43671
|
*
|
|
43350
43672
|
* @private internal utility of `promptbookCli`
|
|
43351
43673
|
*/
|
|
43352
|
-
async function $applyHarnessInstallationStatus(status) {
|
|
43674
|
+
async function $applyHarnessInstallationStatus(status, questionsOptions) {
|
|
43353
43675
|
const { definition, installationState, installedVersion } = status;
|
|
43354
43676
|
if (installationState === 'up-to-date') {
|
|
43355
43677
|
console.info(colors.gray(`✔ ${definition.label} ${installedVersion} is up to date.`));
|
|
@@ -43365,17 +43687,17 @@ async function $applyHarnessInstallationStatus(status) {
|
|
|
43365
43687
|
}
|
|
43366
43688
|
console.warn(colors.yellow(formatHarnessInstallationWarning(status)));
|
|
43367
43689
|
if (installationState === 'not-installed') {
|
|
43368
|
-
await $applyMissingHarnessInstallation(definition);
|
|
43690
|
+
await $applyMissingHarnessInstallation(definition, questionsOptions);
|
|
43369
43691
|
return;
|
|
43370
43692
|
}
|
|
43371
|
-
await $applyOutdatedHarnessInstallation(status);
|
|
43693
|
+
await $applyOutdatedHarnessInstallation(status, questionsOptions);
|
|
43372
43694
|
}
|
|
43373
43695
|
/**
|
|
43374
43696
|
* Offers to install a missing harness globally through npm.
|
|
43375
43697
|
*/
|
|
43376
|
-
async function $applyMissingHarnessInstallation(definition) {
|
|
43698
|
+
async function $applyMissingHarnessInstallation(definition, questionsOptions) {
|
|
43377
43699
|
const installCommand = buildHarnessInstallCommand(definition);
|
|
43378
|
-
const isInstallationApproved = await $askForNpmPackageInstallationApproval(`Install ${definition.label} globally now
|
|
43700
|
+
const isInstallationApproved = await $askForNpmPackageInstallationApproval(`Install ${definition.label} globally now?`, questionsOptions);
|
|
43379
43701
|
if (!isInstallationApproved) {
|
|
43380
43702
|
console.info(colors.gray(`Skipped, run \`${installCommand}\` to do it manually.`));
|
|
43381
43703
|
return;
|
|
@@ -43390,14 +43712,14 @@ async function $applyMissingHarnessInstallation(definition) {
|
|
|
43390
43712
|
/**
|
|
43391
43713
|
* Offers to update an outdated harness exactly where it is installed.
|
|
43392
43714
|
*/
|
|
43393
|
-
async function $applyOutdatedHarnessInstallation(status) {
|
|
43715
|
+
async function $applyOutdatedHarnessInstallation(status, questionsOptions) {
|
|
43394
43716
|
const { definition, latestVersion, installationOrigin } = status;
|
|
43395
43717
|
const updatePlan = resolveHarnessUpdatePlan(definition, installationOrigin.installationMethod);
|
|
43396
43718
|
if (updatePlan.command === null || !updatePlan.isRunnableByPromptbook) {
|
|
43397
43719
|
console.info(colors.gray(formatHarnessManualUpdateInstruction(status, updatePlan)));
|
|
43398
43720
|
return;
|
|
43399
43721
|
}
|
|
43400
|
-
const isUpdateApproved = await $askForNpmPackageInstallationApproval(`Update ${definition.label} to ${latestVersion} with \`${updatePlan.command}\` now
|
|
43722
|
+
const isUpdateApproved = await $askForNpmPackageInstallationApproval(`Update ${definition.label} to ${latestVersion} with \`${updatePlan.command}\` now?`, questionsOptions);
|
|
43401
43723
|
if (!isUpdateApproved) {
|
|
43402
43724
|
console.info(colors.gray(`Skipped, run \`${updatePlan.command}\` to do it manually.`));
|
|
43403
43725
|
return;
|
|
@@ -43833,7 +44155,7 @@ function resolveHarnessInstallationState(installedVersion, latestVersion, isHarn
|
|
|
43833
44155
|
// Note: [🟡] Code for CLI harness installation check [$checkHarnessInstallation](src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts) should never be published outside of `@promptbook/cli`
|
|
43834
44156
|
|
|
43835
44157
|
/**
|
|
43836
|
-
* Checks that every given CLI coding harness is installed globally and, when enabled, up to date.
|
|
44158
|
+
* Checks that every given CLI coding harness is installed globally and, when the questions are enabled, up to date.
|
|
43837
44159
|
* Offers to install missing harnesses and update outdated ones.
|
|
43838
44160
|
*
|
|
43839
44161
|
* Harness names which are `undefined`, for example when no `--harness` is selected in a dry run,
|
|
@@ -43843,15 +44165,18 @@ function resolveHarnessInstallationState(installedVersion, latestVersion, isHarn
|
|
|
43843
44165
|
*
|
|
43844
44166
|
* @private internal utility of `promptbookCli`
|
|
43845
44167
|
*/
|
|
43846
|
-
async function $ensureHarnessInstallations(harnessNames,
|
|
44168
|
+
async function $ensureHarnessInstallations(harnessNames, questionsOptions) {
|
|
43847
44169
|
const definitions = resolveCheckedHarnessDefinitions(harnessNames);
|
|
43848
44170
|
if (definitions.length === 0) {
|
|
43849
44171
|
return;
|
|
43850
44172
|
}
|
|
44173
|
+
// Note: An outdated harness can be updated only after the user confirms it, so `--no-questions`
|
|
44174
|
+
// skips the slower npm registry lookup entirely and only reports what is installed.
|
|
44175
|
+
const isHarnessUpdateCheckEnabled = questionsOptions.isAskingQuestionsEnabled;
|
|
43851
44176
|
// Note: Detection of all harnesses runs in parallel, the questions have to be asked one by one
|
|
43852
44177
|
const statuses = await Promise.all(definitions.map((definition) => $checkHarnessInstallation(definition, isHarnessUpdateCheckEnabled)));
|
|
43853
44178
|
for (const status of statuses) {
|
|
43854
|
-
await $applyHarnessInstallationStatus(status);
|
|
44179
|
+
await $applyHarnessInstallationStatus(status, questionsOptions);
|
|
43855
44180
|
}
|
|
43856
44181
|
}
|
|
43857
44182
|
/**
|
|
@@ -43863,48 +44188,6 @@ function resolveCheckedHarnessDefinitions(harnessNames) {
|
|
|
43863
44188
|
}
|
|
43864
44189
|
// Note: [🟡] Code for CLI harness installation orchestration [$ensureHarnessInstallations](src/cli/cli-commands/common/harness/$ensureHarnessInstallations.ts) should never be published outside of `@promptbook/cli`
|
|
43865
44190
|
|
|
43866
|
-
/**
|
|
43867
|
-
* Registers the shared `--no-harness-update` option on a `ptbk coder` command that uses a coding harness.
|
|
43868
|
-
*
|
|
43869
|
-
* @private internal utility of `promptbookCli`
|
|
43870
|
-
*/
|
|
43871
|
-
function addHarnessUpdateOption(command) {
|
|
43872
|
-
command.option('--no-harness-update', 'Skip checking whether the installed coding harnesses are up to date');
|
|
43873
|
-
}
|
|
43874
|
-
/**
|
|
43875
|
-
* Converts the Commander harness-update flag into the normalized harness-check option.
|
|
43876
|
-
*
|
|
43877
|
-
* @private internal utility of `promptbookCli`
|
|
43878
|
-
*/
|
|
43879
|
-
function normalizeHarnessUpdateCliOptions(cliOptions) {
|
|
43880
|
-
return {
|
|
43881
|
-
isHarnessUpdateCheckEnabled: cliOptions.harnessUpdate,
|
|
43882
|
-
};
|
|
43883
|
-
}
|
|
43884
|
-
// Note: [🟡] Code for CLI harness update options [harnessUpdateCliOptions](src/cli/cli-commands/common/harnessUpdateCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
43885
|
-
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
43886
|
-
|
|
43887
|
-
/**
|
|
43888
|
-
* Relative path to the Promptbook Coder quick-reference file initialized in project roots.
|
|
43889
|
-
*
|
|
43890
|
-
* @private internal utility of `ptbk coder`
|
|
43891
|
-
*/
|
|
43892
|
-
const AGENT_CODING_FILE_PATH = 'AGENT_CODING.md';
|
|
43893
|
-
/**
|
|
43894
|
-
* Returns the default coder `AGENT_CODING.md` quick-reference content.
|
|
43895
|
-
*
|
|
43896
|
-
* @private internal utility of `ptbk coder`
|
|
43897
|
-
*/
|
|
43898
|
-
function getDefaultCoderAgentCodingFileContent() {
|
|
43899
|
-
return spaceTrim$1(`
|
|
43900
|
-
# ✨ Promptbook Coder agent coding
|
|
43901
|
-
|
|
43902
|
-
This project is using [Promptbook Coder](https://coder.ptbk.io) or run \`ptbk coder\`!
|
|
43903
|
-
`);
|
|
43904
|
-
}
|
|
43905
|
-
// Note: [🟡] Code for coder AGENT_CODING file boilerplate [agentCodingFile](src/cli/cli-commands/coder/agentCodingFile.ts) should never be published outside of `@promptbook/cli`
|
|
43906
|
-
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
43907
|
-
|
|
43908
44191
|
/**
|
|
43909
44192
|
* Relative path to the shared coder context file initialized in project roots.
|
|
43910
44193
|
*
|
|
@@ -44006,6 +44289,51 @@ function formatDisplayPath(relativePath) {
|
|
|
44006
44289
|
}
|
|
44007
44290
|
// Note: [🟡] Code for coder path formatting [formatDisplayPath](src/cli/cli-commands/coder/formatDisplayPath.ts) should never be published outside of `@promptbook/cli`
|
|
44008
44291
|
|
|
44292
|
+
/**
|
|
44293
|
+
* Creates the artifact definition of one project-owned coder prompt template.
|
|
44294
|
+
*/
|
|
44295
|
+
function createCoderPromptTemplateArtifactDefinition(definition) {
|
|
44296
|
+
return {
|
|
44297
|
+
relativeFilePath: definition.relativeFilePath,
|
|
44298
|
+
ensureArtifactFile: (projectPath) => ensureDefaultCoderPromptTemplateFile(projectPath, definition),
|
|
44299
|
+
};
|
|
44300
|
+
}
|
|
44301
|
+
/**
|
|
44302
|
+
* Every artifact which the default coder scripts can reference.
|
|
44303
|
+
*/
|
|
44304
|
+
const CODER_REFERENCED_ARTIFACT_DEFINITIONS = [
|
|
44305
|
+
{
|
|
44306
|
+
relativeFilePath: CODER_DEVELOPER_AGENT_FILE_PATH,
|
|
44307
|
+
ensureArtifactFile: ensureCoderDeveloperAgentFile,
|
|
44308
|
+
},
|
|
44309
|
+
{
|
|
44310
|
+
relativeFilePath: AGENTS_FILE_PATH,
|
|
44311
|
+
ensureArtifactFile: (projectPath) => ensureCoderMarkdownFile(projectPath, AGENTS_FILE_PATH, getDefaultCoderAgentsFileContent()),
|
|
44312
|
+
},
|
|
44313
|
+
...getDefaultCoderProjectPromptTemplateDefinitions().map(createCoderPromptTemplateArtifactDefinition),
|
|
44314
|
+
];
|
|
44315
|
+
/**
|
|
44316
|
+
* Creates only those referenced artifacts which the freshly added coder scripts point at.
|
|
44317
|
+
*
|
|
44318
|
+
* An artifact of a script which the project already defines is intentionally **not** created - the project-owned
|
|
44319
|
+
* script is kept as is, so it does not reference the default artifact in the first place.
|
|
44320
|
+
*
|
|
44321
|
+
* @private function of `initializeCoderProjectConfiguration`
|
|
44322
|
+
*/
|
|
44323
|
+
async function ensureCoderReferencedArtifacts(projectPath, referencedArtifactPaths) {
|
|
44324
|
+
const ensuredArtifacts = [];
|
|
44325
|
+
for (const { relativeFilePath, ensureArtifactFile } of CODER_REFERENCED_ARTIFACT_DEFINITIONS) {
|
|
44326
|
+
if (!referencedArtifactPaths.has(relativeFilePath)) {
|
|
44327
|
+
ensuredArtifacts.push({ relativeFilePath, status: 'not-referenced' });
|
|
44328
|
+
continue;
|
|
44329
|
+
}
|
|
44330
|
+
ensuredArtifacts.push({ relativeFilePath, status: await ensureArtifactFile(projectPath) });
|
|
44331
|
+
}
|
|
44332
|
+
return ensuredArtifacts;
|
|
44333
|
+
}
|
|
44334
|
+
// Note: [🟡] Code for coder init referenced artifacts [coderReferencedArtifacts](src/cli/cli-commands/coder/coderReferencedArtifacts.ts) should never be published outside of `@promptbook/cli`
|
|
44335
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44336
|
+
|
|
44009
44337
|
/**
|
|
44010
44338
|
* Fallback `.env` content used when no required variables need to be appended.
|
|
44011
44339
|
*/
|
|
@@ -44100,26 +44428,79 @@ async function ensureCoderGitignoreRules(projectPath, rules) {
|
|
|
44100
44428
|
}
|
|
44101
44429
|
// Note: [🟡] Code for coder init gitignore bootstrapping [ensureCoderGitignoreFile](src/cli/cli-commands/coder/ensureCoderGitignoreFile.ts) should never be published outside of `@promptbook/cli`
|
|
44102
44430
|
|
|
44431
|
+
/**
|
|
44432
|
+
* Name of the npm script which `ptbk coder run` uses to verify the project.
|
|
44433
|
+
*/
|
|
44434
|
+
const CODER_TEST_SCRIPT_NAME = 'test-for-ptbk-coder';
|
|
44103
44435
|
/**
|
|
44104
44436
|
* Default npm scripts initialized by `ptbk coder init`.
|
|
44437
|
+
*
|
|
44438
|
+
* Note: Using NPX because `ptbk` can be installed globally or locally, and NPX will resolve it correctly in either case.
|
|
44105
44439
|
*/
|
|
44106
|
-
const
|
|
44107
|
-
|
|
44108
|
-
|
|
44109
|
-
|
|
44110
|
-
|
|
44111
|
-
|
|
44112
|
-
|
|
44113
|
-
|
|
44440
|
+
const DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS = [
|
|
44441
|
+
{
|
|
44442
|
+
scriptName: 'coder:generate-boilerplates',
|
|
44443
|
+
scriptCommand: `npx ptbk coder generate-boilerplates --count ${DEFAULT_BOILERPLATE_COUNT_OPTION_VALUE} --template ${formatCoderScriptFilePath(COMMON_PROMPT_TEMPLATE_FILE_PATH)}`,
|
|
44444
|
+
referencedArtifactPaths: [COMMON_PROMPT_TEMPLATE_FILE_PATH],
|
|
44445
|
+
},
|
|
44446
|
+
{
|
|
44447
|
+
scriptName: 'coder:add',
|
|
44448
|
+
scriptCommand: `npx ptbk coder add --template ${formatCoderScriptFilePath(COMMON_PROMPT_TEMPLATE_FILE_PATH)}`,
|
|
44449
|
+
referencedArtifactPaths: [COMMON_PROMPT_TEMPLATE_FILE_PATH],
|
|
44450
|
+
},
|
|
44451
|
+
{
|
|
44452
|
+
scriptName: 'coder:run',
|
|
44453
|
+
scriptCommand: [
|
|
44454
|
+
'npx ptbk coder run --harness openai-codex --model gpt-5.6-terra --thinking-level max',
|
|
44455
|
+
`--agent ${formatDisplayPath(CODER_DEVELOPER_AGENT_FILE_PATH)}`,
|
|
44456
|
+
`--context ${formatDisplayPath(AGENTS_FILE_PATH)}`,
|
|
44457
|
+
`--test "npm run ${CODER_TEST_SCRIPT_NAME}" --test-before yes-and-fix`,
|
|
44458
|
+
].join(' '),
|
|
44459
|
+
referencedArtifactPaths: [CODER_DEVELOPER_AGENT_FILE_PATH, AGENTS_FILE_PATH],
|
|
44460
|
+
},
|
|
44461
|
+
// { scriptName: 'coder:find-refactor-candidates', scriptCommand: 'npx ptbk coder find-refactor-candidates', referencedArtifactPaths: [] },
|
|
44462
|
+
{
|
|
44463
|
+
scriptName: 'coder:verify',
|
|
44464
|
+
scriptCommand: 'npx ptbk coder verify',
|
|
44465
|
+
referencedArtifactPaths: [],
|
|
44466
|
+
},
|
|
44467
|
+
{
|
|
44468
|
+
// Note: The verification command of `coder:run` is a project-owned script, so every project can decide
|
|
44469
|
+
// what "verified" means without touching the `coder:run` script itself
|
|
44470
|
+
scriptName: CODER_TEST_SCRIPT_NAME,
|
|
44471
|
+
scriptCommand: 'npm test',
|
|
44472
|
+
referencedArtifactPaths: [],
|
|
44473
|
+
},
|
|
44474
|
+
];
|
|
44114
44475
|
/**
|
|
44115
44476
|
* Lists the default npm scripts initialized by `ptbk coder init`.
|
|
44116
44477
|
*
|
|
44117
44478
|
* @private internal utility of `coder init` command
|
|
44118
44479
|
*/
|
|
44119
44480
|
function getDefaultCoderPackageJsonScripts() {
|
|
44120
|
-
return
|
|
44481
|
+
return Object.fromEntries(DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS.map(({ scriptName, scriptCommand }) => [
|
|
44482
|
+
scriptName,
|
|
44483
|
+
scriptCommand,
|
|
44484
|
+
]));
|
|
44485
|
+
}
|
|
44486
|
+
/**
|
|
44487
|
+
* Collects the project-relative artifact paths referenced by the given default coder scripts.
|
|
44488
|
+
*
|
|
44489
|
+
* @private internal utility of `coder init` command
|
|
44490
|
+
*/
|
|
44491
|
+
function resolveCoderPackageJsonScriptReferencedArtifactPaths(scriptNames) {
|
|
44492
|
+
return new Set(DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS.filter(({ scriptName }) => scriptNames.includes(scriptName))
|
|
44493
|
+
.map(({ referencedArtifactPaths }) => referencedArtifactPaths)
|
|
44494
|
+
.flat());
|
|
44495
|
+
}
|
|
44496
|
+
/**
|
|
44497
|
+
* Formats one project-relative path as an explicitly project-rooted path usable inside a shell command.
|
|
44498
|
+
*/
|
|
44499
|
+
function formatCoderScriptFilePath(relativeFilePath) {
|
|
44500
|
+
return `./${formatDisplayPath(relativeFilePath)}`;
|
|
44121
44501
|
}
|
|
44122
44502
|
// Note: [🟡] Code for coder init package scripts [getDefaultCoderPackageJsonScripts](src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts) should never be published outside of `@promptbook/cli`
|
|
44503
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44123
44504
|
|
|
44124
44505
|
/**
|
|
44125
44506
|
* Loads the TypeScript runtime used for parsing JSONC-style project files.
|
|
@@ -44152,6 +44533,9 @@ const DEFAULT_JSON_FILE_NEWLINE = '\n';
|
|
|
44152
44533
|
/**
|
|
44153
44534
|
* Ensures one JSON object field contains the provided string-record entries.
|
|
44154
44535
|
*
|
|
44536
|
+
* Entries which the project already defines are **never** overridden - only missing keys are added,
|
|
44537
|
+
* so hand-tuned scripts and settings survive every repeated `ptbk coder init`.
|
|
44538
|
+
*
|
|
44155
44539
|
* @private function of `initializeCoderProjectConfiguration`
|
|
44156
44540
|
*/
|
|
44157
44541
|
async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldPath, nextEntries, ensureParentDirectoryPath, }) {
|
|
@@ -44163,21 +44547,24 @@ async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldP
|
|
|
44163
44547
|
const formatting = detectJsonFileFormatting(fileContent);
|
|
44164
44548
|
const jsonObject = fileContent === undefined ? {} : await parseJsonObjectFile(relativeFilePath, fileContent);
|
|
44165
44549
|
const existingEntries = getStringRecordOrDefault(jsonObject[fieldPath], relativeFilePath, fieldPath);
|
|
44166
|
-
|
|
44550
|
+
const addedEntryKeys = [];
|
|
44167
44551
|
const mergedEntries = { ...existingEntries };
|
|
44168
44552
|
for (const [entryKey, entryValue] of Object.entries(nextEntries)) {
|
|
44169
|
-
if (mergedEntries
|
|
44170
|
-
|
|
44171
|
-
|
|
44553
|
+
if (Object.prototype.hasOwnProperty.call(mergedEntries, entryKey)) {
|
|
44554
|
+
// Note: The project already defines this entry, keep its own value untouched
|
|
44555
|
+
continue;
|
|
44172
44556
|
}
|
|
44557
|
+
mergedEntries[entryKey] = entryValue;
|
|
44558
|
+
addedEntryKeys.push(entryKey);
|
|
44173
44559
|
}
|
|
44560
|
+
const hasChanges = fileContent === undefined || addedEntryKeys.length > 0;
|
|
44174
44561
|
if (!hasChanges) {
|
|
44175
|
-
return 'unchanged';
|
|
44562
|
+
return { status: 'unchanged', addedEntryKeys };
|
|
44176
44563
|
}
|
|
44177
44564
|
const nextJsonObject = { ...jsonObject };
|
|
44178
44565
|
nextJsonObject[fieldPath] = mergedEntries;
|
|
44179
44566
|
await writeFile(absoluteFilePath, serializeJsonObject(nextJsonObject, formatting), 'utf-8');
|
|
44180
|
-
return fileContent === undefined ? 'created' : 'updated';
|
|
44567
|
+
return { status: fileContent === undefined ? 'created' : 'updated', addedEntryKeys };
|
|
44181
44568
|
}
|
|
44182
44569
|
/**
|
|
44183
44570
|
* Parses one JSON object file while accepting VS Code style comments and trailing commas.
|
|
@@ -44266,6 +44653,8 @@ const PACKAGE_JSON_FILE_PATH = 'package.json';
|
|
|
44266
44653
|
/**
|
|
44267
44654
|
* Ensures `package.json` contains the standalone Promptbook coder helper scripts.
|
|
44268
44655
|
*
|
|
44656
|
+
* Scripts which the project already defines are kept as they are, only missing ones are added.
|
|
44657
|
+
*
|
|
44269
44658
|
* @private function of `initializeCoderProjectConfiguration`
|
|
44270
44659
|
*/
|
|
44271
44660
|
async function ensureCoderPackageJsonFile(projectPath) {
|
|
@@ -44319,17 +44708,20 @@ const VSCODE_DIRECTORY_PATH = '.vscode';
|
|
|
44319
44708
|
/**
|
|
44320
44709
|
* Ensures VS Code routes pasted prompt images into `prompts/screenshots`.
|
|
44321
44710
|
*
|
|
44711
|
+
* Settings which the project already defines are kept as they are, only missing ones are added.
|
|
44712
|
+
*
|
|
44322
44713
|
* @private function of `initializeCoderProjectConfiguration`
|
|
44323
44714
|
*/
|
|
44324
44715
|
async function ensureCoderVscodeSettingsFile(projectPath) {
|
|
44325
44716
|
const [fieldPath, nextEntries] = resolveDefaultCoderVscodeSettingsEntry();
|
|
44326
|
-
|
|
44717
|
+
const { status } = await mergeStringRecordJsonFile({
|
|
44327
44718
|
projectPath,
|
|
44328
44719
|
relativeFilePath: VSCODE_SETTINGS_FILE_PATH,
|
|
44329
44720
|
fieldPath,
|
|
44330
44721
|
nextEntries,
|
|
44331
44722
|
ensureParentDirectoryPath: VSCODE_DIRECTORY_PATH,
|
|
44332
44723
|
});
|
|
44724
|
+
return status;
|
|
44333
44725
|
}
|
|
44334
44726
|
/**
|
|
44335
44727
|
* Resolves the default string-record entry that `coder init` merges into VS Code settings.
|
|
@@ -44346,34 +44738,32 @@ function resolveDefaultCoderVscodeSettingsEntry() {
|
|
|
44346
44738
|
/**
|
|
44347
44739
|
* Creates or updates all coder configuration artifacts required in the current project.
|
|
44348
44740
|
*
|
|
44741
|
+
* Nothing the project already owns is ever overwritten - existing scripts, settings and files are kept as they are,
|
|
44742
|
+
* and the artifacts they would reference are created only together with the scripts which actually reference them.
|
|
44743
|
+
*
|
|
44349
44744
|
* @private internal utility of `coder init` command
|
|
44350
44745
|
*/
|
|
44351
44746
|
async function initializeCoderProjectConfiguration(projectPath) {
|
|
44352
44747
|
const promptsDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_DIRECTORY_PATH$1);
|
|
44353
44748
|
const promptsDoneDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_DONE_DIRECTORY_PATH);
|
|
44354
44749
|
const promptsTemplatesDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_TEMPLATES_DIRECTORY_PATH);
|
|
44355
|
-
const promptTemplateFileStatuses = await ensureDefaultCoderPromptTemplateFiles(projectPath);
|
|
44356
44750
|
const agentsDirectoryStatus = await ensureDirectory(projectPath, CODER_AGENTS_DIRECTORY_PATH);
|
|
44357
|
-
const developerAgentFileStatus = await ensureCoderDeveloperAgentFile(projectPath);
|
|
44358
|
-
const agentsFileStatus = await ensureCoderMarkdownFile(projectPath, AGENTS_FILE_PATH, getDefaultCoderAgentsFileContent());
|
|
44359
|
-
const agentCodingFileStatus = await ensureCoderMarkdownFile(projectPath, AGENT_CODING_FILE_PATH, getDefaultCoderAgentCodingFileContent());
|
|
44360
44751
|
const { envFileStatus, initializedEnvVariableNames } = await ensureCoderEnvFile(projectPath);
|
|
44361
44752
|
const gitignoreFileStatus = await ensureCoderGitignoreFile(projectPath);
|
|
44362
|
-
const packageJsonFileStatus = await ensureCoderPackageJsonFile(projectPath);
|
|
44753
|
+
const { status: packageJsonFileStatus, addedEntryKeys: addedPackageJsonScriptNames } = await ensureCoderPackageJsonFile(projectPath);
|
|
44363
44754
|
const vscodeSettingsFileStatus = await ensureCoderVscodeSettingsFile(projectPath);
|
|
44755
|
+
const referencedArtifactStatuses = await ensureCoderReferencedArtifacts(projectPath, resolveCoderPackageJsonScriptReferencedArtifactPaths(addedPackageJsonScriptNames));
|
|
44364
44756
|
return {
|
|
44365
44757
|
promptsDirectoryStatus,
|
|
44366
44758
|
promptsDoneDirectoryStatus,
|
|
44367
44759
|
promptsTemplatesDirectoryStatus,
|
|
44368
|
-
promptTemplateFileStatuses,
|
|
44369
44760
|
agentsDirectoryStatus,
|
|
44370
|
-
developerAgentFileStatus,
|
|
44371
|
-
agentsFileStatus,
|
|
44372
|
-
agentCodingFileStatus,
|
|
44373
44761
|
envFileStatus,
|
|
44374
44762
|
gitignoreFileStatus,
|
|
44375
44763
|
packageJsonFileStatus,
|
|
44376
44764
|
vscodeSettingsFileStatus,
|
|
44765
|
+
addedPackageJsonScriptNames,
|
|
44766
|
+
referencedArtifactStatuses,
|
|
44377
44767
|
initializedEnvVariableNames,
|
|
44378
44768
|
};
|
|
44379
44769
|
}
|
|
@@ -44389,17 +44779,20 @@ function printInitializationSummary(summary) {
|
|
|
44389
44779
|
printInitializationStatusLine('prompts/', summary.promptsDirectoryStatus);
|
|
44390
44780
|
printInitializationStatusLine('prompts/done/', summary.promptsDoneDirectoryStatus);
|
|
44391
44781
|
printInitializationStatusLine('prompts/templates/', summary.promptsTemplatesDirectoryStatus);
|
|
44392
|
-
for (const templateFileStatus of summary.promptTemplateFileStatuses) {
|
|
44393
|
-
printInitializationStatusLine(formatDisplayPath(templateFileStatus.relativeFilePath), templateFileStatus.status);
|
|
44394
|
-
}
|
|
44395
44782
|
printInitializationStatusLine('agents/', summary.agentsDirectoryStatus);
|
|
44396
|
-
printInitializationStatusLine(CODER_DEVELOPER_AGENT_FILE_PATH, summary.developerAgentFileStatus);
|
|
44397
|
-
printInitializationStatusLine(AGENTS_FILE_PATH, summary.agentsFileStatus);
|
|
44398
|
-
printInitializationStatusLine(AGENT_CODING_FILE_PATH, summary.agentCodingFileStatus);
|
|
44399
44783
|
printInitializationStatusLine('.env', summary.envFileStatus);
|
|
44400
44784
|
printInitializationStatusLine('.gitignore', summary.gitignoreFileStatus);
|
|
44401
44785
|
printInitializationStatusLine('package.json', summary.packageJsonFileStatus);
|
|
44402
44786
|
printInitializationStatusLine('.vscode/settings.json', summary.vscodeSettingsFileStatus);
|
|
44787
|
+
for (const referencedArtifactStatus of summary.referencedArtifactStatuses) {
|
|
44788
|
+
printInitializationStatusLine(formatDisplayPath(referencedArtifactStatus.relativeFilePath), referencedArtifactStatus.status);
|
|
44789
|
+
}
|
|
44790
|
+
if (summary.addedPackageJsonScriptNames.length > 0) {
|
|
44791
|
+
printInitializationNote(`Added npm scripts: ${summary.addedPackageJsonScriptNames.join(', ')}`, colors.cyan);
|
|
44792
|
+
}
|
|
44793
|
+
else {
|
|
44794
|
+
printInitializationNote('All Promptbook coder npm scripts are already present.', colors.gray);
|
|
44795
|
+
}
|
|
44403
44796
|
if (summary.initializedEnvVariableNames.length > 0) {
|
|
44404
44797
|
printInitializationNote(`Added env variables: ${summary.initializedEnvVariableNames.join(', ')}`, colors.cyan);
|
|
44405
44798
|
}
|
|
@@ -44417,6 +44810,9 @@ function formatInitializationStatus(status) {
|
|
|
44417
44810
|
if (status === 'updated') {
|
|
44418
44811
|
return 'updated';
|
|
44419
44812
|
}
|
|
44813
|
+
if (status === 'not-referenced') {
|
|
44814
|
+
return 'not referenced by the added scripts, kept as is';
|
|
44815
|
+
}
|
|
44420
44816
|
return 'unchanged';
|
|
44421
44817
|
}
|
|
44422
44818
|
/**
|
|
@@ -44459,39 +44855,48 @@ function $initializeCoderInitCommand(program) {
|
|
|
44459
44855
|
${block(listDefaultCoderProjectPromptTemplateDisplayPaths())}
|
|
44460
44856
|
- ${CODER_DEVELOPER_AGENT_FILE_PATH}
|
|
44461
44857
|
- ${AGENTS_FILE_PATH}
|
|
44462
|
-
- ${AGENT_CODING_FILE_PATH}
|
|
44463
44858
|
- .gitignore with local artifacts from every supported harness
|
|
44464
44859
|
- package.json
|
|
44465
44860
|
- .vscode/settings.json
|
|
44466
44861
|
|
|
44862
|
+
Never overwrites what the project already owns:
|
|
44863
|
+
- Existing package.json scripts and .vscode/settings.json settings are kept, only missing ones are added
|
|
44864
|
+
- Files referenced by a script, like the agent and context of coder:run, are created only together
|
|
44865
|
+
with the script which references them
|
|
44866
|
+
|
|
44467
44867
|
Ensures required coding-agent environment variables in .env:
|
|
44468
44868
|
- CODING_AGENT_GIT_NAME
|
|
44469
44869
|
- CODING_AGENT_GIT_EMAIL
|
|
44470
44870
|
- CODING_AGENT_GIT_SIGNING_KEY
|
|
44471
44871
|
|
|
44472
|
-
Checks that the coding harnesses are installed and up to date unless \`--no-
|
|
44872
|
+
Checks that the coding harnesses are installed and up to date unless \`--no-questions\` is used:
|
|
44473
44873
|
${block(listCheckedHarnessLabels())}
|
|
44474
44874
|
|
|
44475
44875
|
${block(CODER_GIT_SYNC_DESCRIPTION)}
|
|
44876
|
+
|
|
44877
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
44476
44878
|
`));
|
|
44477
44879
|
addCoderGitSyncOptions(command);
|
|
44478
|
-
|
|
44880
|
+
addQuestionsOption(command);
|
|
44479
44881
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44480
44882
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
44481
|
-
const
|
|
44883
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
44482
44884
|
const projectPath = process.cwd();
|
|
44483
44885
|
// Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
|
|
44484
44886
|
const { $commitCoderChanges, $startCoderGitSync } = await Promise.resolve().then(function () { return coderGitSync; });
|
|
44485
44887
|
const commitScope = await $startCoderGitSync({ gitSync, projectPath });
|
|
44888
|
+
const isPromptsDirectoryEmpty = await isDirectoryEmpty(projectPath, PROMPTS_DIRECTORY_PATH$1);
|
|
44486
44889
|
const summary = await initializeCoderProjectConfiguration(projectPath);
|
|
44487
44890
|
printInitializationSummary(summary);
|
|
44488
|
-
|
|
44891
|
+
if (isPromptsDirectoryEmpty) {
|
|
44892
|
+
await generatePromptBoilerplate({ projectPath, boilerplateCount: DEFAULT_BOILERPLATE_COUNT });
|
|
44893
|
+
}
|
|
44489
44894
|
await $commitCoderChanges({
|
|
44490
44895
|
gitSync,
|
|
44491
44896
|
commitScope,
|
|
44492
44897
|
commitMessage: 'Initialize Promptbook Coder',
|
|
44493
44898
|
});
|
|
44494
|
-
await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES,
|
|
44899
|
+
await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES, questionsOptions);
|
|
44495
44900
|
}));
|
|
44496
44901
|
}
|
|
44497
44902
|
/**
|
|
@@ -44548,6 +44953,23 @@ function addPromptPriorityOptions(command) {
|
|
|
44548
44953
|
// Note: [🟡] Code for CLI prompt priority options [promptPriorityCliOptions](src/cli/cli-commands/common/promptPriorityCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
44549
44954
|
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44550
44955
|
|
|
44956
|
+
/**
|
|
44957
|
+
* Description shared by coder commands which accept an agent Book.
|
|
44958
|
+
*
|
|
44959
|
+
* @private internal utility of `ptbk coder`
|
|
44960
|
+
*/
|
|
44961
|
+
const CODER_AGENT_OPTION_DESCRIPTION = 'Path to a .book file used to personalize coding prompts and select agent-specific tasks';
|
|
44962
|
+
/**
|
|
44963
|
+
* Registers the shared `--agent` option for coder commands.
|
|
44964
|
+
*
|
|
44965
|
+
* @private internal utility of `ptbk coder`
|
|
44966
|
+
*/
|
|
44967
|
+
function addCoderAgentOption(command) {
|
|
44968
|
+
command.option('--agent <agent-book-path>', CODER_AGENT_OPTION_DESCRIPTION);
|
|
44969
|
+
}
|
|
44970
|
+
// Note: [🟡] Code for CLI coder agent options should never be published outside of `@promptbook/cli`
|
|
44971
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44972
|
+
|
|
44551
44973
|
/**
|
|
44552
44974
|
* Initializes `coder list` command for Promptbook CLI utilities.
|
|
44553
44975
|
*
|
|
@@ -44565,19 +44987,27 @@ function $initializeCoderListCommand(program) {
|
|
|
44565
44987
|
Features:
|
|
44566
44988
|
- Lists only ready, fully authored prompts
|
|
44567
44989
|
- Groups prompts from highest to lowest priority
|
|
44568
|
-
- Optional --harness and --
|
|
44990
|
+
- Optional --harness, --model and --agent filters show only prompts compatible with that selection
|
|
44569
44991
|
- Does not start a coding harness or modify prompt files
|
|
44570
44992
|
`));
|
|
44571
44993
|
addPromptRunnerSelectionOptions(command);
|
|
44994
|
+
addCoderAgentOption(command);
|
|
44572
44995
|
addPromptPriorityOptions(command);
|
|
44573
44996
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44574
|
-
const { priority, minPriority: minimumPriority, maxPriority: maximumPriority, } = cliOptions;
|
|
44997
|
+
const { agent, priority, minPriority: minimumPriority, maxPriority: maximumPriority, } = cliOptions;
|
|
44575
44998
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: false });
|
|
44576
|
-
const
|
|
44999
|
+
const resolvedCoderAgentBook = agent === undefined
|
|
45000
|
+
? undefined
|
|
45001
|
+
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; }))
|
|
45002
|
+
.resolveCoderAgentBook(agent, process.cwd());
|
|
45003
|
+
const promptRunnerIdentity = runnerOptions.agentName === undefined &&
|
|
45004
|
+
runnerOptions.model === undefined &&
|
|
45005
|
+
resolvedCoderAgentBook === undefined
|
|
44577
45006
|
? undefined
|
|
44578
45007
|
: {
|
|
44579
45008
|
harnessName: runnerOptions.agentName,
|
|
44580
45009
|
modelName: runnerOptions.model,
|
|
45010
|
+
agentReferences: resolvedCoderAgentBook === null || resolvedCoderAgentBook === void 0 ? void 0 : resolvedCoderAgentBook.agentReferences,
|
|
44581
45011
|
};
|
|
44582
45012
|
// Note: Import dynamically to avoid loading prompt parsing dependencies until this command is used.
|
|
44583
45013
|
const { listCoderPrompts } = await Promise.resolve().then(function () { return listCoderPrompts$1; });
|
|
@@ -44645,7 +45075,7 @@ function parseOptionalPeriodDuration(optionName, value) {
|
|
|
44645
45075
|
*
|
|
44646
45076
|
* @private internal utility of `ptbk coder`
|
|
44647
45077
|
*/
|
|
44648
|
-
async function $ensureCoderHarnessGitignoreRules(projectPath, harnessName) {
|
|
45078
|
+
async function $ensureCoderHarnessGitignoreRules(projectPath, harnessName, questionsOptions) {
|
|
44649
45079
|
if (harnessName === undefined) {
|
|
44650
45080
|
return;
|
|
44651
45081
|
}
|
|
@@ -44656,7 +45086,7 @@ async function $ensureCoderHarnessGitignoreRules(projectPath, harnessName) {
|
|
|
44656
45086
|
const { label } = getHarnessDefinition(harnessName);
|
|
44657
45087
|
const formattedRules = formatGitignoreRules(missingRules);
|
|
44658
45088
|
const entryLabel = missingRules.length === 1 ? 'entry' : 'entries';
|
|
44659
|
-
const isAdditionApproved = await $askForConfirmation(`Add the missing ${label} ignore ${entryLabel} ${formattedRules} to \`.gitignore\` now
|
|
45089
|
+
const isAdditionApproved = await $askForConfirmation(`Add the missing ${label} ignore ${entryLabel} ${formattedRules} to \`.gitignore\` now?`, questionsOptions);
|
|
44660
45090
|
if (!isAdditionApproved) {
|
|
44661
45091
|
console.info(colors.gray(`Skipped, add ${formattedRules} to \`.gitignore\` manually.`));
|
|
44662
45092
|
return;
|
|
@@ -44681,22 +45111,24 @@ function formatGitignoreRules(rules) {
|
|
|
44681
45111
|
*/
|
|
44682
45112
|
function $initializeCoderPingCommand(program) {
|
|
44683
45113
|
const command = program.command('ping');
|
|
44684
|
-
command.description(spaceTrim$1(`
|
|
44685
|
-
|
|
45114
|
+
command.description(spaceTrim$1((block) => `
|
|
45115
|
+
Send one tiny dummy prompt to a harness and model to measure and warm them up
|
|
44686
45116
|
|
|
44687
|
-
|
|
45117
|
+
${block(PROMPT_RUNNER_DESCRIPTION)}
|
|
44688
45118
|
|
|
44689
|
-
|
|
44690
|
-
|
|
44691
|
-
|
|
44692
|
-
|
|
44693
|
-
|
|
44694
|
-
|
|
44695
|
-
|
|
44696
|
-
|
|
44697
|
-
|
|
45119
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
45120
|
+
|
|
45121
|
+
Features:
|
|
45122
|
+
- Verifies that the selected harness, model, thinking level and authentication really work
|
|
45123
|
+
- Reports the answer of the harness, the response time and the reported usage
|
|
45124
|
+
- Starts the hourly/weekly quota window before you need it, so it is already refreshing when you do
|
|
45125
|
+
- Optional --period keeps the quota window refreshing by pinging once per period until stopped
|
|
45126
|
+
- Makes no coding changes or commits; if the selected harness has missing local ignore rules, offers to add them to .gitignore
|
|
45127
|
+
- Checks that the selected harness is installed and up to date unless --no-questions is used
|
|
45128
|
+
- Use --no-ui to stream the raw harness output instead of only the compact result
|
|
45129
|
+
`));
|
|
44698
45130
|
addPromptRunnerSelectionOptions(command);
|
|
44699
|
-
|
|
45131
|
+
addQuestionsOption(command);
|
|
44700
45132
|
addPromptRunnerRuntimeOptions(command);
|
|
44701
45133
|
command.option('--period <duration>', spaceTrim$1(`
|
|
44702
45134
|
Keep pinging once per period instead of pinging only once.
|
|
@@ -44705,11 +45137,11 @@ function $initializeCoderPingCommand(program) {
|
|
|
44705
45137
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44706
45138
|
const { period: periodValue } = cliOptions;
|
|
44707
45139
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: true });
|
|
44708
|
-
const
|
|
45140
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
44709
45141
|
// Note: The period is validated before the harness installation check, so a mistyped duration fails fast
|
|
44710
45142
|
const periodMs = parseOptionalPeriodDuration('--period', periodValue);
|
|
44711
|
-
await $ensureHarnessInstallations([runnerOptions.agentName],
|
|
44712
|
-
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
45143
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
45144
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName, questionsOptions);
|
|
44713
45145
|
const pingOptions = {
|
|
44714
45146
|
agentName: runnerOptions.agentName,
|
|
44715
45147
|
model: runnerOptions.model,
|
|
@@ -44732,6 +45164,159 @@ function $initializeCoderPingCommand(program) {
|
|
|
44732
45164
|
// Note: [🟡] Code for CLI command [ping](src/cli/cli-commands/coder/ping.ts) should never be published outside of `@promptbook/cli`
|
|
44733
45165
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
44734
45166
|
|
|
45167
|
+
/**
|
|
45168
|
+
* Free disk space below which `ptbk coder` refuses to start a new run.
|
|
45169
|
+
*
|
|
45170
|
+
* A coding round writes prompt and log artifacts, lets the harness rewrite the project, may install npm packages,
|
|
45171
|
+
* may create a git worktree for `--isolate` and usually runs a build, so a run started with less than this
|
|
45172
|
+
* would very likely die somewhere in the middle with a filesystem error.
|
|
45173
|
+
*
|
|
45174
|
+
* @private internal utility of `promptbookCli`
|
|
45175
|
+
*/
|
|
45176
|
+
const LOW_FREE_DISK_SPACE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
45177
|
+
/**
|
|
45178
|
+
* Free disk space below which a started `ptbk coder` run stops at its next checkpoint and waits until space is freed.
|
|
45179
|
+
*
|
|
45180
|
+
* This limit is lower than `LOW_FREE_DISK_SPACE_BYTES`, because interrupting a run which is already in progress
|
|
45181
|
+
* is more expensive than not starting one at all.
|
|
45182
|
+
*
|
|
45183
|
+
* @private internal utility of `promptbookCli`
|
|
45184
|
+
*/
|
|
45185
|
+
const CRITICALLY_LOW_FREE_DISK_SPACE_BYTES = 1 * 1024 * 1024 * 1024;
|
|
45186
|
+
/**
|
|
45187
|
+
* How long one free disk space measurement is reused before the filesystem is measured again during a run.
|
|
45188
|
+
*
|
|
45189
|
+
* Pause checkpoints are passed very often - for example on every tick of a timed wait - so without this
|
|
45190
|
+
* interval the filesystem would be measured many times per second.
|
|
45191
|
+
*
|
|
45192
|
+
* @private internal utility of `promptbookCli`
|
|
45193
|
+
*/
|
|
45194
|
+
const FREE_DISK_SPACE_RECHECK_INTERVAL_MS = 60 * 1000;
|
|
45195
|
+
// Note: [🟡] Code for CLI free disk space handling [freeDiskSpaceConstants](src/cli/cli-commands/common/disk-space/freeDiskSpaceConstants.ts) should never be published outside of `@promptbook/cli`
|
|
45196
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
45197
|
+
|
|
45198
|
+
/**
|
|
45199
|
+
* Classifies one measured amount of free disk space against the `ptbk coder` free disk space limits.
|
|
45200
|
+
*
|
|
45201
|
+
* @private internal utility of `promptbookCli`
|
|
45202
|
+
*/
|
|
45203
|
+
function resolveFreeDiskSpaceLevel(availableBytes) {
|
|
45204
|
+
if (availableBytes < CRITICALLY_LOW_FREE_DISK_SPACE_BYTES) {
|
|
45205
|
+
return 'critical';
|
|
45206
|
+
}
|
|
45207
|
+
if (availableBytes < LOW_FREE_DISK_SPACE_BYTES) {
|
|
45208
|
+
return 'low';
|
|
45209
|
+
}
|
|
45210
|
+
return 'sufficient';
|
|
45211
|
+
}
|
|
45212
|
+
// Note: [🟡] Code for CLI free disk space handling [resolveFreeDiskSpaceLevel](src/cli/cli-commands/common/disk-space/resolveFreeDiskSpaceLevel.ts) should never be published outside of `@promptbook/cli`
|
|
45213
|
+
|
|
45214
|
+
/**
|
|
45215
|
+
* Measures the free disk space on the filesystem which hosts the given path.
|
|
45216
|
+
*
|
|
45217
|
+
* Note: `$` is used to indicate that this function is not a pure function - it reads the state of the filesystem
|
|
45218
|
+
*
|
|
45219
|
+
* @returns the measurement, or `null` when the filesystem can not be measured, for example on a platform which
|
|
45220
|
+
* does not report filesystem statistics - a run is never stopped by a measurement which could not be taken
|
|
45221
|
+
* @private internal utility of `promptbookCli`
|
|
45222
|
+
*/
|
|
45223
|
+
async function $readFreeDiskSpaceStatus(inspectedPath) {
|
|
45224
|
+
try {
|
|
45225
|
+
const fileSystemStats = await statfs(inspectedPath);
|
|
45226
|
+
const blockSizeBytes = fileSystemStats.bsize;
|
|
45227
|
+
const availableBytes = fileSystemStats.bavail * blockSizeBytes;
|
|
45228
|
+
const totalBytes = fileSystemStats.blocks * blockSizeBytes;
|
|
45229
|
+
if (!Number.isFinite(availableBytes) || availableBytes < 0) {
|
|
45230
|
+
return null;
|
|
45231
|
+
}
|
|
45232
|
+
return {
|
|
45233
|
+
inspectedPath,
|
|
45234
|
+
availableBytes,
|
|
45235
|
+
totalBytes,
|
|
45236
|
+
level: resolveFreeDiskSpaceLevel(availableBytes),
|
|
45237
|
+
};
|
|
45238
|
+
}
|
|
45239
|
+
catch (_a) {
|
|
45240
|
+
// Note: A path or a platform which can not report its free disk space must not stop `ptbk coder` from running
|
|
45241
|
+
return null;
|
|
45242
|
+
}
|
|
45243
|
+
}
|
|
45244
|
+
// Note: [🟡] Code for CLI free disk space handling [$readFreeDiskSpaceStatus](src/cli/cli-commands/common/disk-space/$readFreeDiskSpaceStatus.ts) should never be published outside of `@promptbook/cli`
|
|
45245
|
+
|
|
45246
|
+
/**
|
|
45247
|
+
* Byte units used when one amount of disk space is written for a human.
|
|
45248
|
+
*/
|
|
45249
|
+
const FREE_DISK_SPACE_BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
45250
|
+
/**
|
|
45251
|
+
* Writes one byte count as a compact human-readable amount of disk space, for example `812 MB` or `1.5 GB`.
|
|
45252
|
+
*
|
|
45253
|
+
* @private internal utility of `promptbookCli`
|
|
45254
|
+
*/
|
|
45255
|
+
function formatFreeDiskSpaceBytes(bytes) {
|
|
45256
|
+
if (!Number.isFinite(bytes) || bytes <= 0) {
|
|
45257
|
+
return '0 B';
|
|
45258
|
+
}
|
|
45259
|
+
const unitIndex = Math.min(FREE_DISK_SPACE_BYTE_UNITS.length - 1, Math.floor(Math.log(bytes) / Math.log(1024)));
|
|
45260
|
+
const value = bytes / Math.pow(1024, unitIndex);
|
|
45261
|
+
// Note: One decimal place only matters for small values, `476 GB` is more readable than `476.3 GB`
|
|
45262
|
+
const decimalPlaceCount = value >= 10 || unitIndex === 0 ? 0 : 1;
|
|
45263
|
+
// Note: An empty decimal place only adds noise, `2 GB` is more readable than `2.0 GB`
|
|
45264
|
+
const displayedValue = value.toFixed(decimalPlaceCount).replace(/\.0$/, '');
|
|
45265
|
+
return `${displayedValue} ${FREE_DISK_SPACE_BYTE_UNITS[unitIndex]}`;
|
|
45266
|
+
}
|
|
45267
|
+
// Note: [🟡] Code for CLI free disk space handling [formatFreeDiskSpaceBytes](src/cli/cli-commands/common/disk-space/formatFreeDiskSpaceBytes.ts) should never be published outside of `@promptbook/cli`
|
|
45268
|
+
|
|
45269
|
+
/**
|
|
45270
|
+
* Writes the shared warning which explains one low free disk space measurement and how to get out of it.
|
|
45271
|
+
*
|
|
45272
|
+
* The very same wording is used by the check which refuses to start a run and by the check which pauses
|
|
45273
|
+
* a run that ran out of disk space while it was working.
|
|
45274
|
+
*
|
|
45275
|
+
* @private internal utility of `promptbookCli`
|
|
45276
|
+
*/
|
|
45277
|
+
function formatLowFreeDiskSpaceWarning(freeDiskSpaceStatus) {
|
|
45278
|
+
const { inspectedPath } = freeDiskSpaceStatus;
|
|
45279
|
+
const availableSpace = formatFreeDiskSpaceBytes(freeDiskSpaceStatus.availableBytes);
|
|
45280
|
+
const totalSpace = formatFreeDiskSpaceBytes(freeDiskSpaceStatus.totalBytes);
|
|
45281
|
+
const requiredSpaceToStart = formatFreeDiskSpaceBytes(LOW_FREE_DISK_SPACE_BYTES);
|
|
45282
|
+
const requiredSpaceToContinue = formatFreeDiskSpaceBytes(CRITICALLY_LOW_FREE_DISK_SPACE_BYTES);
|
|
45283
|
+
return spaceTrim$1(`
|
|
45284
|
+
Only **${availableSpace}** of ${totalSpace} is left on the disk which hosts \`${inspectedPath}\`.
|
|
45285
|
+
|
|
45286
|
+
**\`ptbk coder\` needs at least ${requiredSpaceToStart} of free disk space to start a run and at least ${requiredSpaceToContinue} to keep one running.**
|
|
45287
|
+
|
|
45288
|
+
Actionable hints:
|
|
45289
|
+
- Free up disk space on the drive which hosts \`${inspectedPath}\`.
|
|
45290
|
+
- Remove build artifacts, package caches and \`node_modules\` folders of projects you are not working on.
|
|
45291
|
+
- Remove the temporary worktrees which earlier \`--isolate\` runs left behind.
|
|
45292
|
+
`);
|
|
45293
|
+
}
|
|
45294
|
+
// Note: [🟡] Code for CLI free disk space handling [formatLowFreeDiskSpaceWarning](src/cli/cli-commands/common/disk-space/formatLowFreeDiskSpaceWarning.ts) should never be published outside of `@promptbook/cli`
|
|
45295
|
+
|
|
45296
|
+
/**
|
|
45297
|
+
* Refuses to start one `ptbk coder` command when the disk which hosts the project is nearly full.
|
|
45298
|
+
*
|
|
45299
|
+
* A run which starts without enough free disk space fails somewhere in the middle, after the coding agent has
|
|
45300
|
+
* already rewritten a part of the project, so it is stopped before it writes anything at all.
|
|
45301
|
+
*
|
|
45302
|
+
* Note: `$` is used to indicate that this function is not a pure function - it reads the state of the filesystem
|
|
45303
|
+
*
|
|
45304
|
+
* @throws {LimitReachedError} when there is not enough free disk space left to start
|
|
45305
|
+
* @private internal utility of `promptbookCli`
|
|
45306
|
+
*/
|
|
45307
|
+
async function $assertSufficientFreeDiskSpace(inspectedPath) {
|
|
45308
|
+
const freeDiskSpaceStatus = await $readFreeDiskSpaceStatus(inspectedPath);
|
|
45309
|
+
if (freeDiskSpaceStatus === null || freeDiskSpaceStatus.level === 'sufficient') {
|
|
45310
|
+
return;
|
|
45311
|
+
}
|
|
45312
|
+
throw new LimitReachedError(spaceTrim$1((block) => `
|
|
45313
|
+
There is not enough free disk space to run \`ptbk coder\`.
|
|
45314
|
+
|
|
45315
|
+
${block(formatLowFreeDiskSpaceWarning(freeDiskSpaceStatus))}
|
|
45316
|
+
`));
|
|
45317
|
+
}
|
|
45318
|
+
// Note: [🟡] Code for CLI free disk space handling [$assertSufficientFreeDiskSpace](src/cli/cli-commands/common/disk-space/$assertSufficientFreeDiskSpace.ts) should never be published outside of `@promptbook/cli`
|
|
45319
|
+
|
|
44735
45320
|
/**
|
|
44736
45321
|
* Npm packages which directly provide the `ptbk` executable.
|
|
44737
45322
|
*
|
|
@@ -45060,7 +45645,11 @@ function formatPromptbookCliInstallationLocation(installationLocation) {
|
|
|
45060
45645
|
* @returns `true` when at least one installation was updated and the current coder run should stop
|
|
45061
45646
|
* @private internal utility of `promptbookCli`
|
|
45062
45647
|
*/
|
|
45063
|
-
async function $ensurePromptbookCliInstallations() {
|
|
45648
|
+
async function $ensurePromptbookCliInstallations(questionsOptions) {
|
|
45649
|
+
if (!questionsOptions.isAskingQuestionsEnabled) {
|
|
45650
|
+
// Note: `--no-questions` forbids asking for the approval, so the registry checks would be useless
|
|
45651
|
+
return false;
|
|
45652
|
+
}
|
|
45064
45653
|
if (!process.stdin.isTTY) {
|
|
45065
45654
|
// Note: Non-interactive runs cannot approve an update and should not wait for registry checks
|
|
45066
45655
|
return false;
|
|
@@ -45072,7 +45661,7 @@ async function $ensurePromptbookCliInstallations() {
|
|
|
45072
45661
|
return false;
|
|
45073
45662
|
}
|
|
45074
45663
|
console.warn(colors.yellow(formatPromptbookCliInstallationWarning(outdatedStatuses)));
|
|
45075
|
-
const isUpdateApproved = await $askForNpmPackageInstallationApproval('Update Promptbook CLI now?');
|
|
45664
|
+
const isUpdateApproved = await $askForNpmPackageInstallationApproval('Update Promptbook CLI now?', questionsOptions);
|
|
45076
45665
|
if (!isUpdateApproved) {
|
|
45077
45666
|
reportManualPromptbookCliUpdateCommands(outdatedStatuses);
|
|
45078
45667
|
return false;
|
|
@@ -45139,6 +45728,17 @@ function isTestBeforeMode(value) {
|
|
|
45139
45728
|
return TEST_BEFORE_MODE_VALUES.includes(value);
|
|
45140
45729
|
}
|
|
45141
45730
|
|
|
45731
|
+
/**
|
|
45732
|
+
* Prints why a coder run has ended to the terminal.
|
|
45733
|
+
*
|
|
45734
|
+
* @private internal utility of `coder run` and `coder server` commands
|
|
45735
|
+
*/
|
|
45736
|
+
function printCoderRunFailure(error) {
|
|
45737
|
+
console.error(colors.bgRed(`${error.name}`));
|
|
45738
|
+
console.error(colors.red(formatUnknownErrorDetails(error)));
|
|
45739
|
+
}
|
|
45740
|
+
// Note: [🟡] Code for coder failure reporting [printCoderRunFailure](src/cli/cli-commands/coder/printCoderRunFailure.ts) should never be published outside of `@promptbook/cli`
|
|
45741
|
+
|
|
45142
45742
|
/**
|
|
45143
45743
|
* Initializes `coder run` command for Promptbook CLI utilities
|
|
45144
45744
|
*
|
|
@@ -45148,10 +45748,12 @@ function isTestBeforeMode(value) {
|
|
|
45148
45748
|
*/
|
|
45149
45749
|
function $initializeCoderRunCommand(program) {
|
|
45150
45750
|
const command = program.command('run');
|
|
45151
|
-
command.description(spaceTrim$1(`
|
|
45751
|
+
command.description(spaceTrim$1((block) => `
|
|
45152
45752
|
Execute coding prompts through selected AI agent
|
|
45153
45753
|
|
|
45154
|
-
${PROMPT_RUNNER_DESCRIPTION}
|
|
45754
|
+
${block(PROMPT_RUNNER_DESCRIPTION)}
|
|
45755
|
+
|
|
45756
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
45155
45757
|
|
|
45156
45758
|
Features:
|
|
45157
45759
|
- Automatically stages and commits changes with agent identity unless --no-commit is used
|
|
@@ -45161,9 +45763,11 @@ function $initializeCoderRunCommand(program) {
|
|
|
45161
45763
|
- Optional post-commit git push with explicit --auto-push opt-in
|
|
45162
45764
|
- Optional pre-prompt git pull with explicit --auto-pull opt-in
|
|
45163
45765
|
- Optional --isolate runs every prompt in its own temporary git worktree and merges it back when verified
|
|
45766
|
+
- Saves the run trace of every round into prompts/traces/, named after its prompt file
|
|
45164
45767
|
- Optional --preserve-logs keeps temp prompt/log artifacts after successful rounds
|
|
45165
45768
|
- Optional --no-ui keeps plain streaming console output for logging and debugging
|
|
45166
|
-
-
|
|
45769
|
+
- Refuses to start on a nearly full disk and pauses the run when the free disk space becomes critical, unless --no-questions is used
|
|
45770
|
+
- Checks that the selected harness is installed and up to date before the first prompt unless --no-questions is used
|
|
45167
45771
|
- Offers to add missing project-local ignore rules for the selected harness
|
|
45168
45772
|
- In interactive mode, checks local and global Promptbook CLI installations and offers to update them
|
|
45169
45773
|
- Supports GPG signing of commits
|
|
@@ -45174,8 +45778,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
45174
45778
|
`));
|
|
45175
45779
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
45176
45780
|
addPromptRunnerSelectionOptions(command);
|
|
45177
|
-
|
|
45178
|
-
command
|
|
45781
|
+
addQuestionsOption(command);
|
|
45782
|
+
addCoderAgentOption(command);
|
|
45179
45783
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
45180
45784
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
45181
45785
|
command.addOption(new Option('--test-before <mode>', `Run tests before coding: ${TEST_BEFORE_MODE_VALUES.join(', ')} (defaults to no; uses npm test when --test is omitted)`)
|
|
@@ -45214,7 +45818,7 @@ function $initializeCoderRunCommand(program) {
|
|
|
45214
45818
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
45215
45819
|
isAgentRequired: !dryRun,
|
|
45216
45820
|
});
|
|
45217
|
-
const
|
|
45821
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
45218
45822
|
// [1] Parse the wait options and --no-auto:
|
|
45219
45823
|
// default: run automatically through the queue (no waiting between prompts)
|
|
45220
45824
|
// --no-auto: wait for user confirmation before each prompt (interactive mode)
|
|
@@ -45222,11 +45826,15 @@ function $initializeCoderRunCommand(program) {
|
|
|
45222
45826
|
// --wait-between-prompts: pace from start of one prompt to start of next
|
|
45223
45827
|
// --wait-after-error: wait before retrying after an error (default 10m)
|
|
45224
45828
|
const waitForUser = !auto;
|
|
45225
|
-
|
|
45829
|
+
assertUserConfirmationIsAllowed({ ...questionsOptions, isWaitingForUser: waitForUser });
|
|
45830
|
+
// Note: Checked before anything is installed or written, because installing a harness, updating the
|
|
45831
|
+
// Promptbook CLI and coding itself all need the disk space which is missing
|
|
45832
|
+
await $assertSufficientFreeDiskSpace(process.cwd());
|
|
45833
|
+
if (await $ensurePromptbookCliInstallations(questionsOptions)) {
|
|
45226
45834
|
return process.exit(0);
|
|
45227
45835
|
}
|
|
45228
|
-
await $ensureHarnessInstallations([runnerOptions.agentName],
|
|
45229
|
-
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
45836
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
45837
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName, questionsOptions);
|
|
45230
45838
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
45231
45839
|
const waitBetweenPrompts = parseOptionalWaitDuration(waitBetweenPromptsValue, 0);
|
|
45232
45840
|
const waitAfterError = parseOptionalWaitDuration(waitAfterErrorValue, DEFAULT_WAIT_AFTER_ERROR_MS$1);
|
|
@@ -45259,6 +45867,7 @@ function $initializeCoderRunCommand(program) {
|
|
|
45259
45867
|
allowDestructiveAutoMigrate,
|
|
45260
45868
|
autoPush: runnerOptions.autoPush,
|
|
45261
45869
|
autoPull: runnerOptions.autoPull,
|
|
45870
|
+
isAskingQuestionsEnabled: questionsOptions.isAskingQuestionsEnabled,
|
|
45262
45871
|
};
|
|
45263
45872
|
// Note: Import the function dynamically to avoid loading heavy dependencies until needed
|
|
45264
45873
|
const { runCodexPrompts } = await Promise.resolve().then(function () { return runCodexPrompts$1; });
|
|
@@ -45268,8 +45877,7 @@ function $initializeCoderRunCommand(program) {
|
|
|
45268
45877
|
}
|
|
45269
45878
|
catch (error) {
|
|
45270
45879
|
assertsError(error);
|
|
45271
|
-
|
|
45272
|
-
console.error(colors.red(error.stack || error.message));
|
|
45880
|
+
printCoderRunFailure(error);
|
|
45273
45881
|
return process.exit(1);
|
|
45274
45882
|
}
|
|
45275
45883
|
return process.exit(0);
|
|
@@ -45313,28 +45921,31 @@ const DEFAULT_CODER_SERVER_PORT = '4441';
|
|
|
45313
45921
|
*/
|
|
45314
45922
|
function $initializeCoderServerCommand(program) {
|
|
45315
45923
|
const command = program.command('server');
|
|
45316
|
-
command.description(spaceTrim$1(`
|
|
45317
|
-
|
|
45924
|
+
command.description(spaceTrim$1((block) => `
|
|
45925
|
+
Start a coder server that watches for prompts and serves a kanban web UI
|
|
45318
45926
|
|
|
45319
|
-
|
|
45927
|
+
${block(PROMPT_RUNNER_DESCRIPTION)}
|
|
45320
45928
|
|
|
45321
|
-
|
|
45322
|
-
|
|
45323
|
-
|
|
45324
|
-
|
|
45325
|
-
|
|
45326
|
-
|
|
45327
|
-
|
|
45328
|
-
|
|
45329
|
-
|
|
45330
|
-
|
|
45929
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
45930
|
+
|
|
45931
|
+
Features:
|
|
45932
|
+
- Runs the same prompt processing as \`ptbk coder run\`
|
|
45933
|
+
- Refuses to start on a nearly full disk and pauses the run when the free disk space becomes critical, unless --no-questions is used
|
|
45934
|
+
- Checks that the selected harness is installed and up to date on startup unless --no-questions is used
|
|
45935
|
+
- Offers to add missing project-local ignore rules for the selected harness
|
|
45936
|
+
- Does not exit when all prompts are done; polls for new prompt files instead
|
|
45937
|
+
- Serves a kanban board at http://localhost:<port> for visual progress tracking
|
|
45938
|
+
- Allows editing prompt files directly from the browser (Trello-style)
|
|
45939
|
+
- Play / pause button in the browser stays in sync with the CLI pause state
|
|
45940
|
+
- Terminal controls match \`ptbk coder run\`: P pause/resume, S skip waiting, X end after current prompt
|
|
45941
|
+
`));
|
|
45331
45942
|
command.addOption(new Option('--port <port>', 'Port to start the coder server on')
|
|
45332
45943
|
.env('PTBK_CODER_SERVER_PORT')
|
|
45333
45944
|
.default(DEFAULT_CODER_SERVER_PORT));
|
|
45334
45945
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
45335
45946
|
addPromptRunnerSelectionOptions(command);
|
|
45336
|
-
|
|
45337
|
-
command
|
|
45947
|
+
addQuestionsOption(command);
|
|
45948
|
+
addCoderAgentOption(command);
|
|
45338
45949
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
45339
45950
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
45340
45951
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
@@ -45363,11 +45974,15 @@ function $initializeCoderServerCommand(program) {
|
|
|
45363
45974
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
45364
45975
|
isAgentRequired: !dryRun,
|
|
45365
45976
|
});
|
|
45366
|
-
const
|
|
45367
|
-
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
45368
|
-
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
45977
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
45369
45978
|
// [1] Parse the wait options and --no-auto (same logic as `coder run`)
|
|
45370
45979
|
const waitForUser = !auto;
|
|
45980
|
+
assertUserConfirmationIsAllowed({ ...questionsOptions, isWaitingForUser: waitForUser });
|
|
45981
|
+
// Note: Checked before anything is installed or written, because installing a harness and coding
|
|
45982
|
+
// itself both need the disk space which is missing
|
|
45983
|
+
await $assertSufficientFreeDiskSpace(process.cwd());
|
|
45984
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
45985
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName, questionsOptions);
|
|
45371
45986
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
45372
45987
|
const waitBetweenPrompts = parseOptionalWaitDuration(waitBetweenPromptsValue, 0);
|
|
45373
45988
|
const waitAfterError = parseOptionalWaitDuration(waitAfterErrorValue, DEFAULT_WAIT_AFTER_ERROR_MS$1);
|
|
@@ -45397,6 +46012,7 @@ function $initializeCoderServerCommand(program) {
|
|
|
45397
46012
|
allowDestructiveAutoMigrate,
|
|
45398
46013
|
autoPush: runnerOptions.autoPush,
|
|
45399
46014
|
autoPull: runnerOptions.autoPull,
|
|
46015
|
+
isAskingQuestionsEnabled: questionsOptions.isAskingQuestionsEnabled,
|
|
45400
46016
|
};
|
|
45401
46017
|
// Note: Import dynamically to avoid loading heavy dependencies until needed
|
|
45402
46018
|
const { runCodexPromptsServer } = await Promise.resolve().then(function () { return runCodexPromptsServer$1; });
|
|
@@ -45405,8 +46021,7 @@ function $initializeCoderServerCommand(program) {
|
|
|
45405
46021
|
}
|
|
45406
46022
|
catch (error) {
|
|
45407
46023
|
assertsError(error);
|
|
45408
|
-
|
|
45409
|
-
console.error(colors.red(error.stack || error.message));
|
|
46024
|
+
printCoderRunFailure(error);
|
|
45410
46025
|
return process.exit(1);
|
|
45411
46026
|
}
|
|
45412
46027
|
return process.exit(0);
|
|
@@ -45595,11 +46210,7 @@ function $initializeCoderCommand(program) {
|
|
|
45595
46210
|
$initializeCoderVerifyCommand(coderCommand);
|
|
45596
46211
|
$initializeCoderFindFreshEmojiTagCommand(coderCommand);
|
|
45597
46212
|
// If no subcommand is provided, show help
|
|
45598
|
-
coderCommand
|
|
45599
|
-
console.info(colors.yellow('Please specify a subcommand.'));
|
|
45600
|
-
console.info('');
|
|
45601
|
-
coderCommand.help();
|
|
45602
|
-
});
|
|
46213
|
+
$requireCliSubcommand(coderCommand);
|
|
45603
46214
|
}
|
|
45604
46215
|
// Note: [🟡] Code for CLI command [coder](src/cli/cli-commands/coder.ts) should never be published outside of `@promptbook/cli`
|
|
45605
46216
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -56189,7 +56800,9 @@ function shouldRunInteractiveChatbot(options) {
|
|
|
56189
56800
|
* @private internal function of `promptbookCli`
|
|
56190
56801
|
*/
|
|
56191
56802
|
function $initializeRunCommand(program) {
|
|
56192
|
-
|
|
56803
|
+
// Note: `run` is deprecated, so it is intentionally NOT the default command of `ptbk`
|
|
56804
|
+
// and it must be asked for explicitly
|
|
56805
|
+
const runCommand = program.command('run');
|
|
56193
56806
|
configureRunCommand(runCommand);
|
|
56194
56807
|
runCommand.action(handleActionErrors((pipelineSource, cliOptions) => runCommandAction(pipelineSource, cliOptions)));
|
|
56195
56808
|
}
|
|
@@ -58028,9 +58641,24 @@ function $addGlobalOptionsToCommand(command) {
|
|
|
58028
58641
|
command.option('--remote-server-url <url>', `URL of remote server to use when `, DEFAULT_REMOTE_SERVER_URL);
|
|
58029
58642
|
}
|
|
58030
58643
|
|
|
58644
|
+
/**
|
|
58645
|
+
* Keeps one already registered CLI command out of the help of its parent command while the command itself stays
|
|
58646
|
+
* fully usable - it can still be run, it still has its own help and it is still reachable through `ptbk help <command>`.
|
|
58647
|
+
*
|
|
58648
|
+
* Note: `$` is used to indicate that this function is not a pure function - it changes how the CLI renders its help
|
|
58649
|
+
*
|
|
58650
|
+
* @private utility of CLI
|
|
58651
|
+
*/
|
|
58652
|
+
function $hideCliCommandFromHelp(command) {
|
|
58653
|
+
command._hidden = true;
|
|
58654
|
+
}
|
|
58655
|
+
|
|
58031
58656
|
/**
|
|
58032
58657
|
* Marks one CLI command as deprecated while keeping it available for existing callers.
|
|
58033
58658
|
*
|
|
58659
|
+
* Deprecated commands are not advertised anymore - they are hidden from the list of commands in the help of their
|
|
58660
|
+
* parent command, they warn when they are used and they explain the deprecation in their own help.
|
|
58661
|
+
*
|
|
58034
58662
|
* @private utility of CLI
|
|
58035
58663
|
*/
|
|
58036
58664
|
function $deprecateCliCommand(command, deprecationMessage) {
|
|
@@ -58042,6 +58670,7 @@ function $deprecateCliCommand(command, deprecationMessage) {
|
|
|
58042
58670
|
command.hook('preAction', () => {
|
|
58043
58671
|
console.warn(colors.yellow(createDeprecatedCliCommandWarning(command, deprecationMessage)));
|
|
58044
58672
|
});
|
|
58673
|
+
$hideCliCommandFromHelp(command);
|
|
58045
58674
|
}
|
|
58046
58675
|
/**
|
|
58047
58676
|
* Creates the runtime warning printed before a deprecated CLI command action starts.
|
|
@@ -58109,10 +58738,17 @@ async function promptbookCli() {
|
|
|
58109
58738
|
program.version(PROMPTBOOK_ENGINE_VERSION);
|
|
58110
58739
|
program.description(CLAIM);
|
|
58111
58740
|
// Note: These options are valid for all commands
|
|
58741
|
+
// Note: Commands are listed in the help in the order they are registered,
|
|
58742
|
+
// `coder` is the most used one so it goes first and the deprecated ones,
|
|
58743
|
+
// which `$deprecateTopLevelCommands` hides from the help entirely, go last
|
|
58744
|
+
$initializeCoderCommand(program);
|
|
58745
|
+
$initializeAgentCommand(program);
|
|
58746
|
+
$initializeAgentFolderCommand(program);
|
|
58747
|
+
$initializeAgentsServerCommand(program);
|
|
58112
58748
|
$initializeAboutCommand(program);
|
|
58749
|
+
$initializeHelloCommand(program);
|
|
58113
58750
|
$initializeRunCommand(program);
|
|
58114
58751
|
$initializeLoginCommand(program);
|
|
58115
|
-
$initializeHelloCommand(program);
|
|
58116
58752
|
$initializeMakeCommand(program);
|
|
58117
58753
|
$initializePrettifyCommand(program);
|
|
58118
58754
|
$initializeTestCommand(program);
|
|
@@ -58120,16 +58756,13 @@ async function promptbookCli() {
|
|
|
58120
58756
|
$initializeListScrapersCommand(program);
|
|
58121
58757
|
$initializeStartAgentsServerCommand(program);
|
|
58122
58758
|
$initializeStartPipelinesServerCommand(program);
|
|
58123
|
-
$initializeAgentCommand(program);
|
|
58124
|
-
$initializeAgentFolderCommand(program);
|
|
58125
|
-
$initializeAgentsServerCommand(program);
|
|
58126
|
-
$initializeCoderCommand(program);
|
|
58127
58759
|
$deprecateTopLevelCommands(program);
|
|
58128
58760
|
// TODO: [🧠] Should it be here or not> $addGlobalOptionsToCommand(program);
|
|
58129
58761
|
program.commands.forEach($addGlobalOptionsToCommand);
|
|
58762
|
+
// Note: There is no default command, so `ptbk` without a subcommand asks for one
|
|
58763
|
+
// instead of running the deprecated `ptbk run`
|
|
58130
58764
|
if (commandLineArguments.length === 0) {
|
|
58131
|
-
program
|
|
58132
|
-
return process.exit(0);
|
|
58765
|
+
return $reportMissingCliSubcommand(program);
|
|
58133
58766
|
}
|
|
58134
58767
|
program.parse(process.argv);
|
|
58135
58768
|
}
|
|
@@ -58143,7 +58776,7 @@ function isTopLevelVersionRequested(commandLineArguments) {
|
|
|
58143
58776
|
return firstCommandLineArgument !== undefined && VERSION_OPTION_ARGUMENTS.has(firstCommandLineArgument);
|
|
58144
58777
|
}
|
|
58145
58778
|
/**
|
|
58146
|
-
*
|
|
58779
|
+
* Marks each configured top-level legacy command as deprecated, which keeps it usable but takes it out of the help.
|
|
58147
58780
|
*/
|
|
58148
58781
|
function $deprecateTopLevelCommands(program) {
|
|
58149
58782
|
for (const command of program.commands) {
|
|
@@ -58154,7 +58787,6 @@ function $deprecateTopLevelCommands(program) {
|
|
|
58154
58787
|
}
|
|
58155
58788
|
}
|
|
58156
58789
|
// Note: [🟡] Code for CLI program [promptbookCli](src/cli/promptbookCli.ts) should never be published outside of `@promptbook/cli`
|
|
58157
|
-
// TODO: [🧠] Maybe `run` command the default, instead of `ptbk run ./foo.book` -> `ptbk ./foo.book`
|
|
58158
58790
|
// TODO: [🥠] Do not export, its just for CLI script
|
|
58159
58791
|
// TODO: [🕌] When more functionalities, rename
|
|
58160
58792
|
// Note: 11:11
|
|
@@ -59266,7 +59898,9 @@ const VERCEL_PROVIDER_PROFILE = {
|
|
|
59266
59898
|
*/
|
|
59267
59899
|
function createExecutionToolsFromVercelProvider(options) {
|
|
59268
59900
|
let { title, description } = options;
|
|
59269
|
-
const { vercelProvider, availableModels,
|
|
59901
|
+
const { vercelProvider, availableModels, additionalChatSettings = {} } = options;
|
|
59902
|
+
// <- Note: `userId` is not forwarded, because Vercel AI SDK moved provider-specific settings like `user` from
|
|
59903
|
+
// `vercelProvider.chat(modelName, settings)` into `providerOptions` which are keyed by the provider
|
|
59270
59904
|
if (!/Vercel/i.test(title)) {
|
|
59271
59905
|
title = `${title} (through Vercel)`;
|
|
59272
59906
|
// <- TODO: [🧈] Maybe standartize the suffix
|
|
@@ -59307,10 +59941,7 @@ function createExecutionToolsFromVercelProvider(options) {
|
|
|
59307
59941
|
|
|
59308
59942
|
`));
|
|
59309
59943
|
}
|
|
59310
|
-
const model = await vercelProvider.chat(modelName
|
|
59311
|
-
user: (userId === null || userId === void 0 ? void 0 : userId.toString()) || undefined,
|
|
59312
|
-
...additionalChatSettings,
|
|
59313
|
-
});
|
|
59944
|
+
const model = await vercelProvider.chat(modelName);
|
|
59314
59945
|
const rawPromptContent = templateParameters(content, { ...parameters, modelName });
|
|
59315
59946
|
// Support for passing a chat thread (multi-message conversation)
|
|
59316
59947
|
let promptMessages;
|
|
@@ -59348,14 +59979,9 @@ function createExecutionToolsFromVercelProvider(options) {
|
|
|
59348
59979
|
}
|
|
59349
59980
|
const rawRequest = {
|
|
59350
59981
|
// <- TODO: [☂]
|
|
59351
|
-
inputFormat: 'messages',
|
|
59352
|
-
mode: {
|
|
59353
|
-
type: 'regular',
|
|
59354
|
-
tools: [
|
|
59355
|
-
/* <- TODO: Pass the tools */
|
|
59356
|
-
],
|
|
59357
|
-
},
|
|
59358
59982
|
prompt: promptMessages,
|
|
59983
|
+
// <- TODO: Pass the tools via `tools`
|
|
59984
|
+
...additionalChatSettings,
|
|
59359
59985
|
};
|
|
59360
59986
|
const start = $getCurrentDate();
|
|
59361
59987
|
if (options.isVerbose) {
|
|
@@ -59372,28 +59998,31 @@ function createExecutionToolsFromVercelProvider(options) {
|
|
|
59372
59998
|
if (options.isVerbose) {
|
|
59373
59999
|
console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
|
|
59374
60000
|
}
|
|
59375
|
-
|
|
60001
|
+
// Note: Vercel AI SDK returns ordered content parts, the chat message is made only of the text parts
|
|
60002
|
+
const responseTextParts = rawResponse.content.flatMap((contentPart) => contentPart.type === 'text' ? [contentPart.text] : []);
|
|
60003
|
+
if (responseTextParts.length === 0) {
|
|
59376
60004
|
throw new PipelineExecutionError('No response message');
|
|
59377
60005
|
}
|
|
60006
|
+
const responseText = responseTextParts.join('');
|
|
59378
60007
|
const complete = $getCurrentDate();
|
|
59379
60008
|
const duration = uncertainNumber((new Date(complete).getTime() - new Date(start).getTime()) / 1000);
|
|
59380
60009
|
const usage = {
|
|
59381
60010
|
price: UNCERTAIN_ZERO_VALUE,
|
|
59382
60011
|
duration,
|
|
59383
60012
|
input: {
|
|
59384
|
-
tokensCount: uncertainNumber(rawResponse.usage.
|
|
60013
|
+
tokensCount: uncertainNumber(rawResponse.usage.inputTokens),
|
|
59385
60014
|
...computeUsageCounts(rawPromptContent),
|
|
59386
60015
|
},
|
|
59387
60016
|
output: {
|
|
59388
|
-
tokensCount: uncertainNumber(rawResponse.usage.
|
|
59389
|
-
...computeUsageCounts(
|
|
60017
|
+
tokensCount: uncertainNumber(rawResponse.usage.outputTokens),
|
|
60018
|
+
...computeUsageCounts(responseText),
|
|
59390
60019
|
},
|
|
59391
60020
|
};
|
|
59392
60021
|
return exportJson({
|
|
59393
60022
|
name: 'promptResult',
|
|
59394
60023
|
message: `Result of \`createExecutionToolsFromVercelProvider.callChatModel\``,
|
|
59395
60024
|
value: {
|
|
59396
|
-
content:
|
|
60025
|
+
content: responseText,
|
|
59397
60026
|
modelName,
|
|
59398
60027
|
timing: {
|
|
59399
60028
|
start,
|
|
@@ -74698,13 +75327,15 @@ function findFirstNonEmptyLineIndex(lines, startLine, endLine) {
|
|
|
74698
75327
|
}
|
|
74699
75328
|
|
|
74700
75329
|
/**
|
|
74701
|
-
* Checks whether a prompt is unrestricted or matches the selected harness
|
|
75330
|
+
* Checks whether a prompt is unrestricted or matches the selected harness, model or Book agent.
|
|
74702
75331
|
*
|
|
74703
|
-
* A prompt status line can contain one or more backtick-delimited model or
|
|
74704
|
-
*
|
|
74705
|
-
* `gpt` selects any `gpt-*` model
|
|
75332
|
+
* A prompt status line can contain one or more backtick-delimited model, harness or agent
|
|
75333
|
+
* references. Matching is intentionally based on normalized substrings so a token such as
|
|
75334
|
+
* `gpt` selects any `gpt-*` model, `developer` selects an agent Book named `developer.book`,
|
|
75335
|
+
* and `opus` selects a `claude-opus-*` model.
|
|
74706
75336
|
*/
|
|
74707
75337
|
function isPromptCompatibleWithRunner(file, section, promptRunnerIdentity) {
|
|
75338
|
+
var _a;
|
|
74708
75339
|
if (promptRunnerIdentity === undefined) {
|
|
74709
75340
|
return true;
|
|
74710
75341
|
}
|
|
@@ -74713,7 +75344,11 @@ function isPromptCompatibleWithRunner(file, section, promptRunnerIdentity) {
|
|
|
74713
75344
|
if (requiredRunnerTokens.length === 0) {
|
|
74714
75345
|
return true;
|
|
74715
75346
|
}
|
|
74716
|
-
const normalizedRunnerNames = [
|
|
75347
|
+
const normalizedRunnerNames = [
|
|
75348
|
+
promptRunnerIdentity.harnessName,
|
|
75349
|
+
promptRunnerIdentity.modelName,
|
|
75350
|
+
...((_a = promptRunnerIdentity.agentReferences) !== null && _a !== void 0 ? _a : []),
|
|
75351
|
+
]
|
|
74717
75352
|
.filter((name) => name !== undefined && name.trim() !== '')
|
|
74718
75353
|
.map((name) => normalizeToKebabCase(name))
|
|
74719
75354
|
.filter((name) => name !== '');
|
|
@@ -74724,7 +75359,7 @@ function isPromptCompatibleWithRunner(file, section, promptRunnerIdentity) {
|
|
|
74724
75359
|
});
|
|
74725
75360
|
}
|
|
74726
75361
|
/**
|
|
74727
|
-
* Extracts model and
|
|
75362
|
+
* Extracts model, harness and Book-agent tokens from a prompt status line.
|
|
74728
75363
|
*/
|
|
74729
75364
|
function extractPromptRunnerTokens(statusLine) {
|
|
74730
75365
|
return Array.from(statusLine.matchAll(/`([^`]+)`/gu))
|
|
@@ -74739,7 +75374,7 @@ function extractPromptRunnerTokens(statusLine) {
|
|
|
74739
75374
|
*
|
|
74740
75375
|
* @private internal constant of `parsePromptFile`
|
|
74741
75376
|
*/
|
|
74742
|
-
const
|
|
75377
|
+
const PROMPT_STATUS_LINE_PATTERN = /^\[(?<marker> |-|\.|[xX]|\^|!)\](?<details>.*)$/u;
|
|
74743
75378
|
/**
|
|
74744
75379
|
* Parses a prompt markdown file into sections and metadata.
|
|
74745
75380
|
*/
|
|
@@ -74763,7 +75398,7 @@ function parsePromptFile(filePath, content) {
|
|
|
74763
75398
|
if (firstNonEmptyLine !== undefined) {
|
|
74764
75399
|
const statusLine = (lines[firstNonEmptyLine] || '').trim();
|
|
74765
75400
|
const parsedStatus = parseStatusLine(statusLine);
|
|
74766
|
-
const status = (_a = parsedStatus === null || parsedStatus === void 0 ? void 0 : parsedStatus.status) !== null && _a !== void 0 ? _a : (
|
|
75401
|
+
const status = (_a = parsedStatus === null || parsedStatus === void 0 ? void 0 : parsedStatus.status) !== null && _a !== void 0 ? _a : (PROMPT_STATUS_LINE_PATTERN.test(statusLine) ? 'not-ready' : 'todo');
|
|
74767
75402
|
const priority = (_b = parsedStatus === null || parsedStatus === void 0 ? void 0 : parsedStatus.priority) !== null && _b !== void 0 ? _b : 0;
|
|
74768
75403
|
sections.push({
|
|
74769
75404
|
index,
|
|
@@ -74791,51 +75426,47 @@ function parsePromptFile(filePath, content) {
|
|
|
74791
75426
|
* For [x] done, [!] failed and [^] in-progress prompts, allow metadata after the status marker.
|
|
74792
75427
|
*/
|
|
74793
75428
|
function parseStatusLine(line) {
|
|
74794
|
-
var _a, _b, _c, _d;
|
|
74795
|
-
|
|
74796
|
-
const
|
|
74797
|
-
|
|
75429
|
+
var _a, _b, _c, _d, _e;
|
|
75430
|
+
const statusLineMatch = line.match(PROMPT_STATUS_LINE_PATTERN);
|
|
75431
|
+
const marker = (_a = statusLineMatch === null || statusLineMatch === void 0 ? void 0 : statusLineMatch.groups) === null || _a === void 0 ? void 0 : _a.marker;
|
|
75432
|
+
const details = (_c = (_b = statusLineMatch === null || statusLineMatch === void 0 ? void 0 : statusLineMatch.groups) === null || _b === void 0 ? void 0 : _b.details) !== null && _c !== void 0 ? _c : '';
|
|
75433
|
+
if (marker === 'x' || marker === 'X') {
|
|
75434
|
+
// For done prompts [x], allow any content after (for cost/time metadata).
|
|
74798
75435
|
return { status: 'done', priority: 0 };
|
|
74799
75436
|
}
|
|
74800
|
-
|
|
74801
|
-
|
|
74802
|
-
if (failedMatch) {
|
|
75437
|
+
if (marker === '!') {
|
|
75438
|
+
// For failed prompts [!], allow any content after (for failure metadata).
|
|
74803
75439
|
return { status: 'failed', priority: 0 };
|
|
74804
75440
|
}
|
|
74805
|
-
|
|
74806
|
-
|
|
74807
|
-
if (inProgressMatch) {
|
|
75441
|
+
if (marker === '^') {
|
|
75442
|
+
// For in-progress prompts [^], allow any content after (for the steps recorded so far).
|
|
74808
75443
|
return { status: 'in-progress', priority: 0 };
|
|
74809
75444
|
}
|
|
74810
|
-
//
|
|
74811
|
-
if (
|
|
75445
|
+
// Treat [.] as the alternative spelling of not-ready [-], preserving the historical clean-line syntax.
|
|
75446
|
+
if ((marker === '-' || marker === '.') && /^[!\s]*$/u.test(details)) {
|
|
74812
75447
|
return { status: 'not-ready', priority: 0 };
|
|
74813
75448
|
}
|
|
74814
|
-
|
|
74815
|
-
// before or after those tokens. Other trailing text remains an invalid status line.
|
|
74816
|
-
const todoMatch = line.match(/^\[ \](?<details>.*)$/u);
|
|
74817
|
-
if (!todoMatch) {
|
|
75449
|
+
if (marker !== ' ') {
|
|
74818
75450
|
return undefined;
|
|
74819
75451
|
}
|
|
74820
|
-
|
|
75452
|
+
// Todo [ ] may contain backtick-delimited model/harness tokens and priority markers
|
|
75453
|
+
// before or after those tokens. Other trailing text remains an invalid status line.
|
|
74821
75454
|
const isPriorityOnly = /^[!\s]*$/u.test(details);
|
|
74822
75455
|
const hasPromptRunnerTokens = extractPromptRunnerTokens(line).length > 0;
|
|
74823
75456
|
if (details.trim() !== '' && !isPriorityOnly && !hasPromptRunnerTokens) {
|
|
74824
75457
|
return undefined;
|
|
74825
75458
|
}
|
|
74826
|
-
return { status: 'todo', priority: (
|
|
75459
|
+
return { status: 'todo', priority: (_e = (_d = details.match(/!/gu)) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0 };
|
|
74827
75460
|
}
|
|
75461
|
+
|
|
74828
75462
|
/**
|
|
74829
|
-
*
|
|
75463
|
+
* HTML comment which excludes a Markdown file from all `ptbk coder` queues.
|
|
74830
75464
|
*
|
|
74831
|
-
* @private internal
|
|
75465
|
+
* @private internal constant of `loadPromptFiles`
|
|
74832
75466
|
*/
|
|
74833
|
-
|
|
74834
|
-
return PROMPT_STATUS_MARKER_PATTERN.test(line);
|
|
74835
|
-
}
|
|
74836
|
-
|
|
75467
|
+
const PTBK_CODER_IGNORE_MARKER = '<!--ptbk-coder-ignore-->';
|
|
74837
75468
|
/**
|
|
74838
|
-
* Loads and parses prompt files from the prompts directory.
|
|
75469
|
+
* Loads and parses prompt files from the prompts directory, excluding files marked for `ptbk coder` to ignore.
|
|
74839
75470
|
*/
|
|
74840
75471
|
async function loadPromptFiles(promptsDir) {
|
|
74841
75472
|
const entries = await readdir(promptsDir, { withFileTypes: true });
|
|
@@ -74846,6 +75477,9 @@ async function loadPromptFiles(promptsDir) {
|
|
|
74846
75477
|
const promptFiles = [];
|
|
74847
75478
|
for (const filePath of files) {
|
|
74848
75479
|
const content = await readFile(filePath, 'utf-8');
|
|
75480
|
+
if (content.includes(PTBK_CODER_IGNORE_MARKER)) {
|
|
75481
|
+
continue;
|
|
75482
|
+
}
|
|
74849
75483
|
promptFiles.push(parsePromptFile(filePath, content));
|
|
74850
75484
|
}
|
|
74851
75485
|
return promptFiles;
|
|
@@ -74955,6 +75589,77 @@ var findUnwrittenPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
|
74955
75589
|
findUnwrittenPrompts: findUnwrittenPrompts
|
|
74956
75590
|
});
|
|
74957
75591
|
|
|
75592
|
+
/**
|
|
75593
|
+
* Reads an optional agent `.book` file and prepares the references that route prompts to it.
|
|
75594
|
+
*
|
|
75595
|
+
* Returns `undefined` when no agent path is provided.
|
|
75596
|
+
*/
|
|
75597
|
+
async function resolveCoderAgentBook(agentBookReference, currentWorkingDirectory) {
|
|
75598
|
+
const normalizedAgentBookReference = agentBookReference === null || agentBookReference === void 0 ? void 0 : agentBookReference.trim();
|
|
75599
|
+
if (!normalizedAgentBookReference) {
|
|
75600
|
+
return undefined;
|
|
75601
|
+
}
|
|
75602
|
+
const resolvedAgentBookPath = resolve(currentWorkingDirectory, normalizedAgentBookReference);
|
|
75603
|
+
const agentSource = (await readFile(resolvedAgentBookPath, 'utf-8').catch((error) => {
|
|
75604
|
+
if (error.code === 'ENOENT' || error.code === 'EISDIR') {
|
|
75605
|
+
throw new NotFoundError(spaceTrim(`
|
|
75606
|
+
Agent book \`${normalizedAgentBookReference}\` was not found or is not a file.
|
|
75607
|
+
|
|
75608
|
+
Pass a path to a \`.book\` file in \`--agent\`.
|
|
75609
|
+
`));
|
|
75610
|
+
}
|
|
75611
|
+
throw error;
|
|
75612
|
+
}));
|
|
75613
|
+
return {
|
|
75614
|
+
agentSource,
|
|
75615
|
+
agentReferences: createCoderAgentReferences({
|
|
75616
|
+
agentBookReference: normalizedAgentBookReference,
|
|
75617
|
+
resolvedAgentBookPath,
|
|
75618
|
+
currentWorkingDirectory,
|
|
75619
|
+
agentSource,
|
|
75620
|
+
}),
|
|
75621
|
+
};
|
|
75622
|
+
}
|
|
75623
|
+
/**
|
|
75624
|
+
* Reads an optional agent `.book` file and compiles its system message for injection into coder prompts.
|
|
75625
|
+
*
|
|
75626
|
+
* Returns `undefined` when no agent path is provided.
|
|
75627
|
+
*/
|
|
75628
|
+
async function resolveCoderAgent(agentBookReference, currentWorkingDirectory) {
|
|
75629
|
+
const resolvedAgentBook = await resolveCoderAgentBook(agentBookReference, currentWorkingDirectory);
|
|
75630
|
+
if (resolvedAgentBook === undefined) {
|
|
75631
|
+
return undefined;
|
|
75632
|
+
}
|
|
75633
|
+
return {
|
|
75634
|
+
...resolvedAgentBook,
|
|
75635
|
+
systemMessage: await createAgentRunnerSystemMessage(resolvedAgentBook.agentSource),
|
|
75636
|
+
};
|
|
75637
|
+
}
|
|
75638
|
+
/**
|
|
75639
|
+
* Creates the path and Book-title aliases which a prompt can use to target one selected agent.
|
|
75640
|
+
*
|
|
75641
|
+
* @private internal utility of `resolveCoderAgentBook`
|
|
75642
|
+
*/
|
|
75643
|
+
function createCoderAgentReferences(options) {
|
|
75644
|
+
const relativeAgentBookPath = relative(options.currentWorkingDirectory, options.resolvedAgentBookPath).replaceAll('\\', '/');
|
|
75645
|
+
const agentBookFileName = basename(options.resolvedAgentBookPath);
|
|
75646
|
+
const agentBookName = basename(options.resolvedAgentBookPath, extname(options.resolvedAgentBookPath));
|
|
75647
|
+
const agentNameFromBook = parseAgentSource(options.agentSource).agentName;
|
|
75648
|
+
return Array.from(new Set([
|
|
75649
|
+
options.agentBookReference,
|
|
75650
|
+
relativeAgentBookPath,
|
|
75651
|
+
agentBookFileName,
|
|
75652
|
+
agentBookName,
|
|
75653
|
+
agentNameFromBook,
|
|
75654
|
+
].filter((agentReference) => agentReference.trim() !== '')));
|
|
75655
|
+
}
|
|
75656
|
+
|
|
75657
|
+
var resolveCoderAgent$1 = /*#__PURE__*/Object.freeze({
|
|
75658
|
+
__proto__: null,
|
|
75659
|
+
resolveCoderAgentBook: resolveCoderAgentBook,
|
|
75660
|
+
resolveCoderAgent: resolveCoderAgent
|
|
75661
|
+
});
|
|
75662
|
+
|
|
74958
75663
|
/**
|
|
74959
75664
|
* Lists todo prompts that are ready to run (no authoring placeholders).
|
|
74960
75665
|
*/
|
|
@@ -75037,23 +75742,6 @@ var listCoderPrompts$1 = /*#__PURE__*/Object.freeze({
|
|
|
75037
75742
|
listCoderPrompts: listCoderPrompts
|
|
75038
75743
|
});
|
|
75039
75744
|
|
|
75040
|
-
/**
|
|
75041
|
-
* Formats one unknown error-like value into its readable message without the stack trace.
|
|
75042
|
-
*
|
|
75043
|
-
* Use this instead of `formatUnknownErrorDetails` whenever the text is shown to the user, for example
|
|
75044
|
-
* inside a branded error, where the stack of the wrapped error would only bury the actual cause.
|
|
75045
|
-
*/
|
|
75046
|
-
function formatUnknownErrorMessage(error) {
|
|
75047
|
-
if (error instanceof Error) {
|
|
75048
|
-
return error.message;
|
|
75049
|
-
}
|
|
75050
|
-
if (typeof error === 'string') {
|
|
75051
|
-
return error;
|
|
75052
|
-
}
|
|
75053
|
-
const serializedError = JSON.stringify(error, null, 2);
|
|
75054
|
-
return serializedError !== null && serializedError !== void 0 ? serializedError : String(error);
|
|
75055
|
-
}
|
|
75056
|
-
|
|
75057
75745
|
/**
|
|
75058
75746
|
* Builds a normalized temporary shell script path for prompt runners.
|
|
75059
75747
|
*/
|
|
@@ -75352,7 +76040,7 @@ const DEFAULT_WAIT_AFTER_ERROR_MS = 10 * 60 * 1000;
|
|
|
75352
76040
|
/**
|
|
75353
76041
|
* CLI usage text for this script.
|
|
75354
76042
|
*/
|
|
75355
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--context <context-or-file>] [--test <test-command...>] [--test-before <no|yes-and-fail|yes-and-fix>] [--preserve-logs] [--isolate] [--no-ui] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--min-priority <minimum-priority>] [--max-priority <maximum-priority>] [--limit <run-count>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--wait-after-prompt <duration>] [--wait-between-prompts <duration>] [--wait-after-error <duration>] [--no-auto] [--no-commit] [--git-changes <fail|ignore|continue>] [--no-normalize-line-endings] [--auto-push] [--auto-pull]';
|
|
76043
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--agent <agent-book-path>] [--context <context-or-file>] [--test <test-command...>] [--test-before <no|yes-and-fail|yes-and-fix>] [--preserve-logs] [--isolate] [--no-ui] [--thinking-level <thinking-level>] [--priority <minimum-priority>] [--min-priority <minimum-priority>] [--max-priority <maximum-priority>] [--limit <run-count>] [--allow-credits] [--auto-migrate] [--allow-destructive-auto-migrate] [--wait-after-prompt <duration>] [--wait-between-prompts <duration>] [--wait-after-error <duration>] [--no-auto] [--no-commit] [--git-changes <fail|ignore|continue>] [--no-normalize-line-endings] [--auto-push] [--auto-pull]';
|
|
75356
76044
|
/**
|
|
75357
76045
|
* Top-level flags supported by this command.
|
|
75358
76046
|
*/
|
|
@@ -75360,6 +76048,7 @@ const KNOWN_OPTION_FLAGS = new Set([
|
|
|
75360
76048
|
'--dry-run',
|
|
75361
76049
|
'--harness',
|
|
75362
76050
|
'--model',
|
|
76051
|
+
'--agent',
|
|
75363
76052
|
'--context',
|
|
75364
76053
|
'--test',
|
|
75365
76054
|
'--test-before',
|
|
@@ -75398,6 +76087,7 @@ function parseRunOptions(args) {
|
|
|
75398
76087
|
}
|
|
75399
76088
|
}
|
|
75400
76089
|
const model = readOptionValue(args, '--model');
|
|
76090
|
+
const agent = readOptionValue(args, '--agent');
|
|
75401
76091
|
const context = readOptionValue(args, '--context');
|
|
75402
76092
|
const hasTestCommandFlag = args.includes('--test');
|
|
75403
76093
|
const testCommand = readVariadicOptionValue(args, '--test');
|
|
@@ -75474,6 +76164,7 @@ function parseRunOptions(args) {
|
|
|
75474
76164
|
noUi,
|
|
75475
76165
|
agentName,
|
|
75476
76166
|
model,
|
|
76167
|
+
agent,
|
|
75477
76168
|
context,
|
|
75478
76169
|
testCommand,
|
|
75479
76170
|
testBefore,
|
|
@@ -75908,30 +76599,43 @@ async function recordPromptDurationSample(key, promptDurationMs) {
|
|
|
75908
76599
|
// Note: [🟡] Code in this file is only used from `@promptbook/cli` orchestration scripts and is not shipped to other consumers.
|
|
75909
76600
|
|
|
75910
76601
|
/**
|
|
75911
|
-
*
|
|
76602
|
+
* Creates the guard which watches the free disk space while one `ptbk coder` run is in progress.
|
|
75912
76603
|
*
|
|
75913
|
-
*
|
|
76604
|
+
* The guard runs at every pause checkpoint of the run. When the disk became critically full it reports the
|
|
76605
|
+
* warning and requests a pause, so the run stops at that checkpoint instead of failing in the middle of a
|
|
76606
|
+
* coding round, and continues once the user has freed some space and pressed `P`.
|
|
76607
|
+
*
|
|
76608
|
+
* @private internal utility of `ptbk coder` free disk space handling
|
|
75914
76609
|
*/
|
|
75915
|
-
|
|
75916
|
-
|
|
75917
|
-
|
|
75918
|
-
|
|
75919
|
-
|
|
75920
|
-
|
|
75921
|
-
|
|
75922
|
-
|
|
75923
|
-
|
|
76610
|
+
function createFreeDiskSpaceGuard(options) {
|
|
76611
|
+
const { inspectedPath, isAskingQuestionsEnabled } = options;
|
|
76612
|
+
let lastMeasurementTimeMs;
|
|
76613
|
+
return async () => {
|
|
76614
|
+
if (lastMeasurementTimeMs !== undefined &&
|
|
76615
|
+
Date.now() - lastMeasurementTimeMs < FREE_DISK_SPACE_RECHECK_INTERVAL_MS) {
|
|
76616
|
+
return;
|
|
76617
|
+
}
|
|
76618
|
+
lastMeasurementTimeMs = Date.now();
|
|
76619
|
+
const freeDiskSpaceStatus = await $readFreeDiskSpaceStatus(inspectedPath);
|
|
76620
|
+
if (freeDiskSpaceStatus === null || freeDiskSpaceStatus.level !== 'critical') {
|
|
76621
|
+
return;
|
|
76622
|
+
}
|
|
76623
|
+
console.warn(colors.yellow(spaceTrim$1((block) => `
|
|
76624
|
+
The disk is running out of space while \`ptbk coder\` is working.
|
|
75924
76625
|
|
|
75925
|
-
|
|
75926
|
-
|
|
76626
|
+
${block(formatLowFreeDiskSpaceWarning(freeDiskSpaceStatus))}
|
|
76627
|
+
- Press \`P\` to continue once the disk space is freed, or start the run with \`--no-questions\` to never pause on a full disk.
|
|
76628
|
+
`)));
|
|
76629
|
+
if (!isAskingQuestionsEnabled) {
|
|
76630
|
+
// Note: `--no-questions` forbids stopping and waiting for somebody who would free the disk space,
|
|
76631
|
+
// so the run keeps going and the warning above is the only thing which is reported
|
|
76632
|
+
return;
|
|
75927
76633
|
}
|
|
75928
|
-
|
|
75929
|
-
|
|
75930
|
-
return {
|
|
75931
|
-
agentSource: agentSource,
|
|
75932
|
-
systemMessage: await createAgentRunnerSystemMessage(agentSource),
|
|
76634
|
+
announcePauseTargetLabel(`continuing with only ${formatFreeDiskSpaceBytes(freeDiskSpaceStatus.availableBytes)} of free disk space left`);
|
|
76635
|
+
requestPause();
|
|
75933
76636
|
};
|
|
75934
76637
|
}
|
|
76638
|
+
// Note: [🟡] Code for `ptbk coder` free disk space handling [createFreeDiskSpaceGuard](scripts/run-codex-prompts/common/createFreeDiskSpaceGuard.ts) should never be published outside of `@promptbook/cli`
|
|
75935
76639
|
|
|
75936
76640
|
/**
|
|
75937
76641
|
* Refresh interval used by the countdown display while waiting.
|
|
@@ -77902,6 +78606,169 @@ async function writePromptFile(file) {
|
|
|
77902
78606
|
await writeFile(file.path, content, 'utf-8');
|
|
77903
78607
|
}
|
|
77904
78608
|
|
|
78609
|
+
/**
|
|
78610
|
+
* Creates a safe markdown fenced code block even when content contains backticks.
|
|
78611
|
+
*
|
|
78612
|
+
* @param content - Raw code content.
|
|
78613
|
+
* @param language - Optional info-string language label.
|
|
78614
|
+
* @returns Fenced code block.
|
|
78615
|
+
*
|
|
78616
|
+
* @private internal utility of `createStandaloneBookLanguageMarkdown` and of the `ptbk coder` run traces
|
|
78617
|
+
*/
|
|
78618
|
+
function getSafeCodeBlock(content, language = 'markdown') {
|
|
78619
|
+
const maxBacktickCount = Math.max(0, ...(content.match(/`+/g) || []).map((match) => match.length));
|
|
78620
|
+
const fence = '`'.repeat(Math.max(3, maxBacktickCount + 1));
|
|
78621
|
+
return `${fence}${language}\n${content}\n${fence}`;
|
|
78622
|
+
}
|
|
78623
|
+
|
|
78624
|
+
/**
|
|
78625
|
+
* Renders the markdown run trace of one finished or failed prompt round.
|
|
78626
|
+
*
|
|
78627
|
+
* The trace pairs the metadata of the round - which harness, model and thinking level ran it, how long each of
|
|
78628
|
+
* its steps took and what it cost - with the untouched runtime log, so a finished round can still be analyzed
|
|
78629
|
+
* after its temporary artifacts are cleaned up.
|
|
78630
|
+
*/
|
|
78631
|
+
function buildPromptRunTraceContent(options) {
|
|
78632
|
+
const sections = [
|
|
78633
|
+
buildPromptRunTraceSummarySection(options),
|
|
78634
|
+
buildPromptRunTraceFailureSection(options.outcome),
|
|
78635
|
+
buildPromptRunTraceRuntimeLogSection(options.runtimeLog),
|
|
78636
|
+
].filter((section) => section !== undefined);
|
|
78637
|
+
return `${sections.join('\n\n')}\n`;
|
|
78638
|
+
}
|
|
78639
|
+
/**
|
|
78640
|
+
* Renders the heading and the metadata bullet list of one run trace.
|
|
78641
|
+
*/
|
|
78642
|
+
function buildPromptRunTraceSummarySection(options) {
|
|
78643
|
+
const { file, section, outcome } = options;
|
|
78644
|
+
const runnerSignature = formatRunnerSignature(options.runnerName, options.modelName, options.thinkingLevel);
|
|
78645
|
+
const loginMethodLabel = outcome.kind === 'succeeded' ? formatCodexLoginMethod(outcome.loginMethod) : undefined;
|
|
78646
|
+
const loginMethodSuffix = loginMethodLabel ? ` (${loginMethodLabel})` : '';
|
|
78647
|
+
const detailLines = [
|
|
78648
|
+
`- **Prompt:** ${buildPromptSummary(file, section)}`,
|
|
78649
|
+
...buildPromptRunTraceSectionLines(file, section),
|
|
78650
|
+
`- **Outcome:** ${formatPromptRunTraceOutcomeLabel(outcome)}`,
|
|
78651
|
+
`- **Runner:** ${runnerSignature}${loginMethodSuffix}`,
|
|
78652
|
+
`- **Attempts:** ${options.attemptCount}`,
|
|
78653
|
+
...buildPromptRunTraceStepsLines(outcome),
|
|
78654
|
+
...buildPromptRunTraceTestCommandLines(options.testCommand),
|
|
78655
|
+
`- **Started:** ${options.startedDate.toISOString()}`,
|
|
78656
|
+
`- **Finished:** ${options.finishedDate.toISOString()}`,
|
|
78657
|
+
`- **Duration:** ${moment.duration(options.finishedDate.diff(options.startedDate)).humanize()}`,
|
|
78658
|
+
];
|
|
78659
|
+
return spaceTrim$1((block) => `
|
|
78660
|
+
# Run trace of \`${buildPromptLabelForDisplay(file, section)}\`
|
|
78661
|
+
|
|
78662
|
+
${block(detailLines.join('\n'))}
|
|
78663
|
+
`);
|
|
78664
|
+
}
|
|
78665
|
+
/**
|
|
78666
|
+
* Renders which section of its prompt file the round implemented.
|
|
78667
|
+
*
|
|
78668
|
+
* A prompt file holding exactly one section says nothing by naming it, exactly like the section suffix of its
|
|
78669
|
+
* generated artifact names, so only a file with more than one section reports the section it traced.
|
|
78670
|
+
*/
|
|
78671
|
+
function buildPromptRunTraceSectionLines(file, section) {
|
|
78672
|
+
if (file.sections.length <= 1) {
|
|
78673
|
+
return [];
|
|
78674
|
+
}
|
|
78675
|
+
return [`- **Prompt section:** ${section.index + 1} of ${file.sections.length}`];
|
|
78676
|
+
}
|
|
78677
|
+
/**
|
|
78678
|
+
* Renders the per-step usage breakdown of a successful round, omitted for a round which never finished one.
|
|
78679
|
+
*/
|
|
78680
|
+
function buildPromptRunTraceStepsLines(outcome) {
|
|
78681
|
+
if (outcome.kind !== 'succeeded') {
|
|
78682
|
+
return [];
|
|
78683
|
+
}
|
|
78684
|
+
const stepsSummary = formatCoderRunSteps(outcome.steps);
|
|
78685
|
+
if (stepsSummary === '') {
|
|
78686
|
+
return [];
|
|
78687
|
+
}
|
|
78688
|
+
return [`- **Steps:** ${stepsSummary}`];
|
|
78689
|
+
}
|
|
78690
|
+
/**
|
|
78691
|
+
* Renders the verification command of the round, omitted when the round ran without one.
|
|
78692
|
+
*/
|
|
78693
|
+
function buildPromptRunTraceTestCommandLines(testCommand) {
|
|
78694
|
+
if (!testCommand) {
|
|
78695
|
+
return [];
|
|
78696
|
+
}
|
|
78697
|
+
return [`- **Verification command:** \`${testCommand}\``];
|
|
78698
|
+
}
|
|
78699
|
+
/**
|
|
78700
|
+
* Renders the failure details of a failed round, omitted for a successful one.
|
|
78701
|
+
*/
|
|
78702
|
+
function buildPromptRunTraceFailureSection(outcome) {
|
|
78703
|
+
if (outcome.kind !== 'failed') {
|
|
78704
|
+
return undefined;
|
|
78705
|
+
}
|
|
78706
|
+
return `## Failure\n\n${getSafeCodeBlock(formatUnknownErrorDetails(outcome.error), 'text')}`;
|
|
78707
|
+
}
|
|
78708
|
+
/**
|
|
78709
|
+
* Renders the untouched runtime log of the round, or says that the round produced none.
|
|
78710
|
+
*/
|
|
78711
|
+
function buildPromptRunTraceRuntimeLogSection(runtimeLog) {
|
|
78712
|
+
if (runtimeLog.trim() === '') {
|
|
78713
|
+
return '## Runtime log\n\n_This round has produced no readable runtime log._';
|
|
78714
|
+
}
|
|
78715
|
+
return `## Runtime log\n\n${getSafeCodeBlock(runtimeLog.replace(/\r\n/gu, '\n').trimEnd(), 'text')}`;
|
|
78716
|
+
}
|
|
78717
|
+
/**
|
|
78718
|
+
* Formats the outcome of the round as the human-readable label of its trace.
|
|
78719
|
+
*/
|
|
78720
|
+
function formatPromptRunTraceOutcomeLabel(outcome) {
|
|
78721
|
+
return outcome.kind === 'succeeded' ? 'Succeeded' : 'Failed';
|
|
78722
|
+
}
|
|
78723
|
+
|
|
78724
|
+
/**
|
|
78725
|
+
* Name of the directory which keeps the run traces inside the prompts directory.
|
|
78726
|
+
*/
|
|
78727
|
+
const PROMPT_RUN_TRACES_DIRECTORY_NAME = 'traces';
|
|
78728
|
+
/**
|
|
78729
|
+
* Builds the path of the run trace which belongs to one prompt section.
|
|
78730
|
+
*
|
|
78731
|
+
* The trace is stored in the `traces` directory of the very same prompts directory the prompt itself lives in,
|
|
78732
|
+
* and it carries the name of its prompt file. A prompt file holding more than one section appends the section
|
|
78733
|
+
* suffix, exactly like the temporary scripts and the isolation worktrees of the same section do.
|
|
78734
|
+
*/
|
|
78735
|
+
function buildPromptRunTracePath(file, section) {
|
|
78736
|
+
const promptFileBaseName = file.name.replace(/\.[^.]+$/u, '');
|
|
78737
|
+
const traceFileName = `${promptFileBaseName}${buildPromptSectionSuffix(file, section)}.md`;
|
|
78738
|
+
return join(dirname(file.path), PROMPT_RUN_TRACES_DIRECTORY_NAME, traceFileName);
|
|
78739
|
+
}
|
|
78740
|
+
|
|
78741
|
+
/**
|
|
78742
|
+
* Writes the run trace of one prompt round into the `traces` directory of the prompts directory.
|
|
78743
|
+
*
|
|
78744
|
+
* Returns the path of the written trace so callers can include it in a commit.
|
|
78745
|
+
*/
|
|
78746
|
+
async function writePromptRunTrace(options) {
|
|
78747
|
+
const { logPath, ...contentOptions } = options;
|
|
78748
|
+
const tracePath = buildPromptRunTracePath(options.file, options.section);
|
|
78749
|
+
const runtimeLog = await readPromptRuntimeLog(logPath);
|
|
78750
|
+
await mkdir(dirname(tracePath), { recursive: true });
|
|
78751
|
+
await writeFile(tracePath, buildPromptRunTraceContent({ ...contentOptions, runtimeLog }), 'utf-8');
|
|
78752
|
+
return tracePath;
|
|
78753
|
+
}
|
|
78754
|
+
/**
|
|
78755
|
+
* Reads the live runtime log of one round.
|
|
78756
|
+
*
|
|
78757
|
+
* A round which never produced a readable log still gets its trace, because the metadata of the round is worth
|
|
78758
|
+
* keeping on its own - so a missing log is reported as empty instead of failing the round which has just passed.
|
|
78759
|
+
*/
|
|
78760
|
+
async function readPromptRuntimeLog(logPath) {
|
|
78761
|
+
if (!logPath) {
|
|
78762
|
+
return '';
|
|
78763
|
+
}
|
|
78764
|
+
try {
|
|
78765
|
+
return await readFile(logPath, 'utf-8');
|
|
78766
|
+
}
|
|
78767
|
+
catch (_a) {
|
|
78768
|
+
return '';
|
|
78769
|
+
}
|
|
78770
|
+
}
|
|
78771
|
+
|
|
77905
78772
|
/**
|
|
77906
78773
|
* Refreshes optional harness subscription usage in the shared coder-run UI state.
|
|
77907
78774
|
*
|
|
@@ -78024,7 +78891,9 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
78024
78891
|
catch (error) {
|
|
78025
78892
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
78026
78893
|
lastError = error;
|
|
78027
|
-
|
|
78894
|
+
// Note: A harness which is not logged in answers every retry the same way, so the user gets
|
|
78895
|
+
// the sign-in instructions right away instead of after every retry has waited its delay
|
|
78896
|
+
if (error instanceof AuthenticationError || errorRetryAttempt >= MAX_RETRY_ATTEMPTS_AFTER_ERROR) {
|
|
78028
78897
|
break;
|
|
78029
78898
|
}
|
|
78030
78899
|
await waitAfterErrorBeforeRetry({
|
|
@@ -78046,6 +78915,7 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
78046
78915
|
attemptCount,
|
|
78047
78916
|
error: lastError,
|
|
78048
78917
|
options,
|
|
78918
|
+
logPath,
|
|
78049
78919
|
roundCommitScope,
|
|
78050
78920
|
uiHandle,
|
|
78051
78921
|
waitForRequestedPause,
|
|
@@ -78162,6 +79032,17 @@ async function finalizeSuccessfulPromptRound(options) {
|
|
|
78162
79032
|
// Note: The prompt status is always written into the original project, an isolated round transports
|
|
78163
79033
|
// its own changes back through the merge instead
|
|
78164
79034
|
await writePromptFile(nextPrompt.file);
|
|
79035
|
+
// Note: Written before the round is committed, so the trace of the round lands in the very same commit
|
|
79036
|
+
// as the prompt it describes, and before the live runtime log it is built from is deleted
|
|
79037
|
+
await recordPromptRoundTrace({
|
|
79038
|
+
options: runOptions,
|
|
79039
|
+
nextPrompt,
|
|
79040
|
+
runnerMetadata,
|
|
79041
|
+
promptExecutionStartedDate,
|
|
79042
|
+
attemptCount: result.attemptCount,
|
|
79043
|
+
logPath,
|
|
79044
|
+
outcome: { kind: 'succeeded', steps: result.steps, loginMethod: result.loginMethod },
|
|
79045
|
+
});
|
|
78165
79046
|
await normalizeLineEndingsForCurrentRound(runOptions, roundProjectPath, roundCommitScope);
|
|
78166
79047
|
await recordPromptDurationInEstimateCache({
|
|
78167
79048
|
options: runOptions,
|
|
@@ -78209,7 +79090,7 @@ async function finalizeSuccessfulPromptRound(options) {
|
|
|
78209
79090
|
* Finalizes a failed prompt round, persisting prompt failure metadata before rethrowing.
|
|
78210
79091
|
*/
|
|
78211
79092
|
async function finalizeFailedPromptRound(options) {
|
|
78212
|
-
const { nextPrompt, runnerMetadata, previousRunnerSignatures, promptExecutionStartedDate, attemptCount, error, options: runOptions, roundCommitScope, uiHandle, waitForRequestedPause, roundProjectPath, } = options;
|
|
79093
|
+
const { nextPrompt, runnerMetadata, previousRunnerSignatures, promptExecutionStartedDate, attemptCount, error, options: runOptions, logPath, roundCommitScope, uiHandle, waitForRequestedPause, roundProjectPath, } = options;
|
|
78213
79094
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
78214
79095
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
78215
79096
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
@@ -78235,8 +79116,42 @@ async function finalizeFailedPromptRound(options) {
|
|
|
78235
79116
|
modelName: runnerMetadata.modelName,
|
|
78236
79117
|
error,
|
|
78237
79118
|
});
|
|
79119
|
+
// Note: A failed round is exactly the round whose trace is worth reading, so it is written before the live
|
|
79120
|
+
// runtime log it is built from is deleted
|
|
79121
|
+
await recordPromptRoundTrace({
|
|
79122
|
+
options: runOptions,
|
|
79123
|
+
nextPrompt,
|
|
79124
|
+
runnerMetadata,
|
|
79125
|
+
promptExecutionStartedDate,
|
|
79126
|
+
attemptCount,
|
|
79127
|
+
logPath,
|
|
79128
|
+
outcome: { kind: 'failed', error },
|
|
79129
|
+
});
|
|
78238
79130
|
await normalizeLineEndingsForCurrentRound(runOptions, roundProjectPath, roundCommitScope);
|
|
78239
79131
|
}
|
|
79132
|
+
/**
|
|
79133
|
+
* Persists the run trace of one prompt round, so the round can still be analyzed after its temporary
|
|
79134
|
+
* artifacts are gone.
|
|
79135
|
+
*
|
|
79136
|
+
* This is the single place where both the successful and the failed round record what they did, which harness,
|
|
79137
|
+
* model and thinking level did it and everything that harness has written while doing it.
|
|
79138
|
+
*/
|
|
79139
|
+
async function recordPromptRoundTrace(options) {
|
|
79140
|
+
const { options: runOptions, nextPrompt, runnerMetadata, promptExecutionStartedDate, attemptCount, logPath, outcome, } = options;
|
|
79141
|
+
await writePromptRunTrace({
|
|
79142
|
+
file: nextPrompt.file,
|
|
79143
|
+
section: nextPrompt.section,
|
|
79144
|
+
runnerName: runnerMetadata.runnerName,
|
|
79145
|
+
modelName: runnerMetadata.modelName,
|
|
79146
|
+
thinkingLevel: runOptions.thinkingLevel,
|
|
79147
|
+
testCommand: runOptions.testCommand,
|
|
79148
|
+
attemptCount,
|
|
79149
|
+
startedDate: promptExecutionStartedDate,
|
|
79150
|
+
finishedDate: moment(),
|
|
79151
|
+
outcome,
|
|
79152
|
+
logPath,
|
|
79153
|
+
});
|
|
79154
|
+
}
|
|
78240
79155
|
/**
|
|
78241
79156
|
* Waits for the optional user confirmation immediately before creating the commit.
|
|
78242
79157
|
*/
|
|
@@ -78885,7 +79800,13 @@ async function recordIsolationMergeFailure(options, worktree, failureDetails) {
|
|
|
78885
79800
|
await commitChanges(buildCoderIsolationMergeFailureCommitMessage(worktree), {
|
|
78886
79801
|
autoPush: options.options.autoPush,
|
|
78887
79802
|
projectPath: worktree.projectPath,
|
|
78888
|
-
|
|
79803
|
+
// Note: The round itself has already succeeded, so it has left its run trace in the original project.
|
|
79804
|
+
// It belongs to this commit, which is the only one this task still gets.
|
|
79805
|
+
relevantPaths: [
|
|
79806
|
+
nextPrompt.file.path,
|
|
79807
|
+
errorLogPath,
|
|
79808
|
+
buildPromptRunTracePath(nextPrompt.file, nextPrompt.section),
|
|
79809
|
+
].map((path) => toProjectRelativeGitPath(worktree.projectPath, path)),
|
|
78889
79810
|
});
|
|
78890
79811
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(mergeFailureError.message);
|
|
78891
79812
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Merging \`${worktree.taskName}\` failed, worktree kept for a manual merge`);
|
|
@@ -79160,12 +80081,23 @@ const PRE_CODING_TEST_CHANGES_COMMIT_MESSAGE = 'test: Apply changes made by pre-
|
|
|
79160
80081
|
* @public exported from `@promptbook/cli`
|
|
79161
80082
|
*/
|
|
79162
80083
|
async function runCodexPrompts(providedOptions) {
|
|
80084
|
+
var _a;
|
|
79163
80085
|
const options = normalizeRunOptions(providedOptions !== null && providedOptions !== void 0 ? providedOptions : parseRunOptions(process.argv.slice(2)));
|
|
79164
80086
|
validateRunCodexPromptOptions(options);
|
|
79165
80087
|
resetCoderRunControls();
|
|
79166
80088
|
const runStartDate = moment();
|
|
79167
80089
|
const { isRichUiEnabled, progressDisplay, uiHandle } = createRunDisplays(options, runStartDate);
|
|
79168
|
-
const waitForRequestedPause = createPauseWaiter({
|
|
80090
|
+
const waitForRequestedPause = createPauseWaiter({
|
|
80091
|
+
isRichUiEnabled,
|
|
80092
|
+
progressDisplay,
|
|
80093
|
+
uiHandle,
|
|
80094
|
+
// Note: Every pause checkpoint of the whole run goes through this one waiter, so watching the free disk
|
|
80095
|
+
// space here covers each round, each verification and each runner without repeating the check
|
|
80096
|
+
guardFreeDiskSpace: createFreeDiskSpaceGuard({
|
|
80097
|
+
inspectedPath: process.cwd(),
|
|
80098
|
+
isAskingQuestionsEnabled: (_a = options.isAskingQuestionsEnabled) !== null && _a !== void 0 ? _a : true,
|
|
80099
|
+
}),
|
|
80100
|
+
});
|
|
79169
80101
|
startPauseListenerIfNeeded(isRichUiEnabled);
|
|
79170
80102
|
try {
|
|
79171
80103
|
const resolvedCoderContext = await resolveCoderContext(options.context, process.cwd());
|
|
@@ -79178,6 +80110,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
79178
80110
|
const promptRunnerIdentity = {
|
|
79179
80111
|
harnessName: options.agentName,
|
|
79180
80112
|
modelName: actualRunnerModel,
|
|
80113
|
+
agentReferences: resolvedCoderAgent === null || resolvedCoderAgent === void 0 ? void 0 : resolvedCoderAgent.agentReferences,
|
|
79181
80114
|
};
|
|
79182
80115
|
console.info(colors.green(`Running prompts with ${runner.name}`));
|
|
79183
80116
|
initializeRunUi(uiHandle, runner.name, actualRunnerModel, options);
|
|
@@ -79614,11 +80547,14 @@ async function commitTestBeforeChangesIfNeeded(options) {
|
|
|
79614
80547
|
* Creates a pause waiter that keeps the progress display and rich UI in sync.
|
|
79615
80548
|
*/
|
|
79616
80549
|
function createPauseWaiter(options) {
|
|
79617
|
-
const { isRichUiEnabled, progressDisplay, uiHandle } = options;
|
|
80550
|
+
const { isRichUiEnabled, progressDisplay, uiHandle, guardFreeDiskSpace } = options;
|
|
79618
80551
|
return async (checkpoint) => {
|
|
79619
80552
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase(checkpoint.phase);
|
|
79620
80553
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(checkpoint.statusMessage);
|
|
79621
80554
|
announcePauseTargetLabel(checkpoint.checkpointLabel);
|
|
80555
|
+
// Note: Runs after the checkpoint label is announced, so a pause requested because of a full disk
|
|
80556
|
+
// replaces that label and says why the run is standing still
|
|
80557
|
+
await guardFreeDiskSpace();
|
|
79622
80558
|
await checkPause({
|
|
79623
80559
|
silent: isRichUiEnabled,
|
|
79624
80560
|
onPaused: () => {
|
|
@@ -79737,7 +80673,7 @@ function finishWhenNoPromptIsAvailable(promptQueueSnapshot, isRichUiEnabled, uiH
|
|
|
79737
80673
|
return false;
|
|
79738
80674
|
}
|
|
79739
80675
|
if (promptQueueSnapshot.stats.forAgent > 0) {
|
|
79740
|
-
announceRunCompletion('No prompts match the selected harness or
|
|
80676
|
+
announceRunCompletion('No prompts match the selected harness, model or agent.', colors.yellow, isRichUiEnabled, uiHandle);
|
|
79741
80677
|
}
|
|
79742
80678
|
else if (promptQueueSnapshot.stats.toBeWritten > 0) {
|
|
79743
80679
|
announceRunCompletion('No prompts ready for agent.', colors.yellow, isRichUiEnabled, uiHandle);
|
|
@@ -79782,7 +80718,7 @@ function finishWhenEndAfterCurrentPromptIsRequested(options) {
|
|
|
79782
80718
|
function announceKeepAliveStatus(promptQueueSnapshot, isRichUiEnabled, uiHandle) {
|
|
79783
80719
|
let message;
|
|
79784
80720
|
if (promptQueueSnapshot.stats.forAgent > 0) {
|
|
79785
|
-
message = 'No prompts match the selected harness or
|
|
80721
|
+
message = 'No prompts match the selected harness, model or agent. Watching for changes...';
|
|
79786
80722
|
}
|
|
79787
80723
|
else if (promptQueueSnapshot.stats.toBeWritten > 0) {
|
|
79788
80724
|
message = 'No prompts ready for agent. Watching for changes...';
|