@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/umd/index.umd.js
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
* @generated
|
|
59
59
|
* @see https://github.com/webgptorg/promptbook
|
|
60
60
|
*/
|
|
61
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
61
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-34';
|
|
62
62
|
/**
|
|
63
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
64
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1718,6 +1718,35 @@
|
|
|
1718
1718
|
// TODO: [🗽] Unite branding and make single place for it
|
|
1719
1719
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1720
1720
|
|
|
1721
|
+
/**
|
|
1722
|
+
* Message printed when one CLI command which only groups subcommands is run without picking any of them.
|
|
1723
|
+
*
|
|
1724
|
+
* @private internal constant of `$requireCliSubcommand`
|
|
1725
|
+
*/
|
|
1726
|
+
const MISSING_CLI_SUBCOMMAND_MESSAGE = 'Please specify a subcommand.';
|
|
1727
|
+
/**
|
|
1728
|
+
* Makes one CLI command which only groups subcommands ask for a subcommand instead of doing anything on its own.
|
|
1729
|
+
*
|
|
1730
|
+
* Note: `$` is used to indicate that this function is not a pure function - it registers an action in the CLI
|
|
1731
|
+
*
|
|
1732
|
+
* @private utility of CLI
|
|
1733
|
+
*/
|
|
1734
|
+
function $requireCliSubcommand(command) {
|
|
1735
|
+
command.action(() => $reportMissingCliSubcommand(command));
|
|
1736
|
+
}
|
|
1737
|
+
/**
|
|
1738
|
+
* Asks for a subcommand of one CLI command, prints its help and exits the process.
|
|
1739
|
+
*
|
|
1740
|
+
* Note: `$` is used to indicate that this function is not a pure function - it writes to the console and exits the process
|
|
1741
|
+
*
|
|
1742
|
+
* @private utility of CLI
|
|
1743
|
+
*/
|
|
1744
|
+
function $reportMissingCliSubcommand(command) {
|
|
1745
|
+
console.info(colors__default["default"].yellow(MISSING_CLI_SUBCOMMAND_MESSAGE));
|
|
1746
|
+
console.info('');
|
|
1747
|
+
return command.help();
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1721
1750
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1722
1751
|
/**
|
|
1723
1752
|
* All CLI harness names supported by `CliAgent` and `ptbk agent exec`.
|
|
@@ -2113,11 +2142,7 @@
|
|
|
2113
2142
|
`));
|
|
2114
2143
|
$initializeAgentChatCommand(agentCommand);
|
|
2115
2144
|
$initializeAgentExecCommand(agentCommand);
|
|
2116
|
-
agentCommand
|
|
2117
|
-
console.info(colors__default["default"].yellow('Please specify a subcommand.'));
|
|
2118
|
-
console.info('');
|
|
2119
|
-
agentCommand.help();
|
|
2120
|
-
});
|
|
2145
|
+
$requireCliSubcommand(agentCommand);
|
|
2121
2146
|
}
|
|
2122
2147
|
// Note: [🟡] Code for CLI command [agent](src/cli/cli-commands/agent.ts) should never be published outside of `@promptbook/cli`
|
|
2123
2148
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -2275,6 +2300,23 @@
|
|
|
2275
2300
|
}
|
|
2276
2301
|
return 'unchanged';
|
|
2277
2302
|
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Checks whether a project-relative directory is missing or contains no entries.
|
|
2305
|
+
*
|
|
2306
|
+
* @private internal utility of `coder init` command
|
|
2307
|
+
*/
|
|
2308
|
+
async function isDirectoryEmpty(projectPath, relativeDirectoryPath) {
|
|
2309
|
+
const directoryPath = path.join(projectPath, relativeDirectoryPath);
|
|
2310
|
+
try {
|
|
2311
|
+
return (await promises.readdir(directoryPath)).length === 0;
|
|
2312
|
+
}
|
|
2313
|
+
catch (error) {
|
|
2314
|
+
if (isNodeJsErrorWithCode$1(error, 'ENOENT')) {
|
|
2315
|
+
return true;
|
|
2316
|
+
}
|
|
2317
|
+
throw error;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2278
2320
|
/**
|
|
2279
2321
|
* Checks whether a path exists and is a directory.
|
|
2280
2322
|
*/
|
|
@@ -2286,6 +2328,12 @@
|
|
|
2286
2328
|
return false;
|
|
2287
2329
|
}
|
|
2288
2330
|
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Checks whether a caught value is a Node.js error with the given error code.
|
|
2333
|
+
*/
|
|
2334
|
+
function isNodeJsErrorWithCode$1(error, code) {
|
|
2335
|
+
return typeof error === 'object' && error !== null && 'code' in error && error.code === code;
|
|
2336
|
+
}
|
|
2289
2337
|
// Note: [🟡] Code for coder init directory creation [ensureDirectory](src/cli/cli-commands/coder/ensureDirectory.ts) should never be published outside of `@promptbook/cli`
|
|
2290
2338
|
|
|
2291
2339
|
/**
|
|
@@ -2573,11 +2621,7 @@
|
|
|
2573
2621
|
$initializeAgentTickCommand(agentFolderCommand);
|
|
2574
2622
|
$initializeAgentRunCommand(agentFolderCommand);
|
|
2575
2623
|
$initializeAgentRunMultipleCommand(agentFolderCommand);
|
|
2576
|
-
agentFolderCommand
|
|
2577
|
-
console.info(colors__default["default"].yellow('Please specify a subcommand.'));
|
|
2578
|
-
console.info('');
|
|
2579
|
-
agentFolderCommand.help();
|
|
2580
|
-
});
|
|
2624
|
+
$requireCliSubcommand(agentFolderCommand);
|
|
2581
2625
|
}
|
|
2582
2626
|
// Note: [🟡] Code for CLI command [agent-folder](src/cli/cli-commands/agent-folder.ts) should never be published outside of `@promptbook/cli`
|
|
2583
2627
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -21428,10 +21472,30 @@
|
|
|
21428
21472
|
return relativePath.replace(/\\/gu, '/');
|
|
21429
21473
|
}
|
|
21430
21474
|
|
|
21475
|
+
/**
|
|
21476
|
+
* AuthenticationError is thrown from login function which is dependency of remote server
|
|
21477
|
+
*
|
|
21478
|
+
* @public exported from `@promptbook/core`
|
|
21479
|
+
*/
|
|
21480
|
+
class AuthenticationError extends Error {
|
|
21481
|
+
constructor(message) {
|
|
21482
|
+
super(message);
|
|
21483
|
+
this.name = 'AuthenticationError';
|
|
21484
|
+
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
21485
|
+
}
|
|
21486
|
+
}
|
|
21487
|
+
|
|
21431
21488
|
/**
|
|
21432
21489
|
* Formats one unknown error-like value into readable text for logs and feedback.
|
|
21490
|
+
*
|
|
21491
|
+
* An `AuthenticationError` is reported without its stack, because its message is written for the user - it
|
|
21492
|
+
* says which harness has to be signed in again and how - and the frames of a failure nobody can debug would
|
|
21493
|
+
* only push those instructions out of sight.
|
|
21433
21494
|
*/
|
|
21434
21495
|
function formatUnknownErrorDetails(error) {
|
|
21496
|
+
if (error instanceof AuthenticationError) {
|
|
21497
|
+
return error.message;
|
|
21498
|
+
}
|
|
21435
21499
|
if (error instanceof Error) {
|
|
21436
21500
|
return error.stack || error.message;
|
|
21437
21501
|
}
|
|
@@ -24148,6 +24212,7 @@
|
|
|
24148
24212
|
commandName: 'codex',
|
|
24149
24213
|
npmPackageName: '@openai/codex',
|
|
24150
24214
|
projectGitignoreRules: ['.codex'],
|
|
24215
|
+
authenticationMethod: { command: 'codex login' },
|
|
24151
24216
|
// Note: The official standalone installer keeps its package in `~/.codex` and links it onto the `PATH`
|
|
24152
24217
|
standaloneInstallation: {
|
|
24153
24218
|
directoryNames: ['.codex'],
|
|
@@ -24160,6 +24225,7 @@
|
|
|
24160
24225
|
commandName: 'copilot',
|
|
24161
24226
|
npmPackageName: '@github/copilot',
|
|
24162
24227
|
projectGitignoreRules: ['.github/copilot/settings.local.json'],
|
|
24228
|
+
authenticationMethod: { command: 'copilot', interactiveStep: 'running the `/login` command inside it' },
|
|
24163
24229
|
// Note: The GitHub Copilot CLI downloads its native binary in a postinstall script
|
|
24164
24230
|
npmInstallEnvironment: { npm_config_ignore_scripts: 'false' },
|
|
24165
24231
|
},
|
|
@@ -24169,6 +24235,7 @@
|
|
|
24169
24235
|
commandName: 'cline',
|
|
24170
24236
|
npmPackageName: 'cline',
|
|
24171
24237
|
projectGitignoreRules: ['.cline'],
|
|
24238
|
+
authenticationMethod: { command: 'cline', interactiveStep: 'signing in to the provider inside it' },
|
|
24172
24239
|
},
|
|
24173
24240
|
'claude-code': {
|
|
24174
24241
|
harnessName: 'claude-code',
|
|
@@ -24176,6 +24243,7 @@
|
|
|
24176
24243
|
commandName: 'claude',
|
|
24177
24244
|
npmPackageName: '@anthropic-ai/claude-code',
|
|
24178
24245
|
projectGitignoreRules: ['.claude'],
|
|
24246
|
+
authenticationMethod: { command: 'claude', interactiveStep: 'running the `/login` command inside it' },
|
|
24179
24247
|
},
|
|
24180
24248
|
opencode: {
|
|
24181
24249
|
harnessName: 'opencode',
|
|
@@ -24183,6 +24251,7 @@
|
|
|
24183
24251
|
commandName: 'opencode',
|
|
24184
24252
|
npmPackageName: 'opencode-ai',
|
|
24185
24253
|
projectGitignoreRules: ['.opencode'],
|
|
24254
|
+
authenticationMethod: { command: 'opencode auth login' },
|
|
24186
24255
|
},
|
|
24187
24256
|
gemini: {
|
|
24188
24257
|
harnessName: 'gemini',
|
|
@@ -24190,6 +24259,7 @@
|
|
|
24190
24259
|
commandName: 'gemini',
|
|
24191
24260
|
npmPackageName: '@google/gemini-cli',
|
|
24192
24261
|
projectGitignoreRules: ['.gemini'],
|
|
24262
|
+
authenticationMethod: { command: 'gemini', interactiveStep: 'running the `/auth` command inside it' },
|
|
24193
24263
|
},
|
|
24194
24264
|
'qwen-code': {
|
|
24195
24265
|
harnessName: 'qwen-code',
|
|
@@ -24197,6 +24267,7 @@
|
|
|
24197
24267
|
commandName: 'qwen',
|
|
24198
24268
|
npmPackageName: '@qwen-code/qwen-code',
|
|
24199
24269
|
projectGitignoreRules: ['.qwen'],
|
|
24270
|
+
authenticationMethod: { command: 'qwen', interactiveStep: 'running the `/auth` command inside it' },
|
|
24200
24271
|
},
|
|
24201
24272
|
};
|
|
24202
24273
|
/**
|
|
@@ -26230,6 +26301,183 @@
|
|
|
26230
26301
|
return `${sessionId.slice(0, 8)}...`;
|
|
26231
26302
|
}
|
|
26232
26303
|
|
|
26304
|
+
/**
|
|
26305
|
+
* Formats one unknown error-like value into its readable message without the stack trace.
|
|
26306
|
+
*
|
|
26307
|
+
* Use this instead of `formatUnknownErrorDetails` whenever the text is shown to the user, for example
|
|
26308
|
+
* inside a branded error, where the stack of the wrapped error would only bury the actual cause.
|
|
26309
|
+
*/
|
|
26310
|
+
function formatUnknownErrorMessage(error) {
|
|
26311
|
+
if (error instanceof Error) {
|
|
26312
|
+
return error.message;
|
|
26313
|
+
}
|
|
26314
|
+
if (typeof error === 'string') {
|
|
26315
|
+
return error;
|
|
26316
|
+
}
|
|
26317
|
+
const serializedError = JSON.stringify(error, null, 2);
|
|
26318
|
+
return serializedError !== null && serializedError !== void 0 ? serializedError : String(error);
|
|
26319
|
+
}
|
|
26320
|
+
|
|
26321
|
+
/**
|
|
26322
|
+
* Builds the branded error which tells the user that the selected harness has to be signed in again.
|
|
26323
|
+
*/
|
|
26324
|
+
function buildHarnessAuthenticationError(options) {
|
|
26325
|
+
const { harnessName, reason } = options;
|
|
26326
|
+
const { label, authenticationMethod } = getHarnessDefinition(harnessName);
|
|
26327
|
+
return new AuthenticationError(spaceTrim((block) => `
|
|
26328
|
+
The **${label}** harness is not authenticated, so the prompt was not run.
|
|
26329
|
+
|
|
26330
|
+
${label} reported:
|
|
26331
|
+
> ${reason}
|
|
26332
|
+
|
|
26333
|
+
${block(buildSignInInstruction(authenticationMethod))}
|
|
26334
|
+
|
|
26335
|
+
Once you are signed in, start the very same \`ptbk coder\` command again.
|
|
26336
|
+
`));
|
|
26337
|
+
}
|
|
26338
|
+
/**
|
|
26339
|
+
* Builds the sentence which tells the user how to sign in to one harness again.
|
|
26340
|
+
*/
|
|
26341
|
+
function buildSignInInstruction(authenticationMethod) {
|
|
26342
|
+
const { command, interactiveStep } = authenticationMethod;
|
|
26343
|
+
if (interactiveStep === undefined) {
|
|
26344
|
+
return `Sign in again by running \`${command}\`.`;
|
|
26345
|
+
}
|
|
26346
|
+
return `Sign in again by running \`${command}\` and then ${interactiveStep}.`;
|
|
26347
|
+
}
|
|
26348
|
+
|
|
26349
|
+
/**
|
|
26350
|
+
* Maximum length of the harness reason quoted back to the user.
|
|
26351
|
+
*/
|
|
26352
|
+
const MAXIMUM_AUTHENTICATION_FAILURE_REASON_LENGTH = 300;
|
|
26353
|
+
/**
|
|
26354
|
+
* Keys of machine-readable harness output whose string value carries the human-readable failure reason.
|
|
26355
|
+
*
|
|
26356
|
+
* Harnesses which stream JSON events - like Claude Code with its `stream-json` output - report the reason only
|
|
26357
|
+
* inside such a value, surrounded by hundreds of characters of session metadata which must never be shown to
|
|
26358
|
+
* the user. The keys are ordered from the most to the least conclusive one.
|
|
26359
|
+
*/
|
|
26360
|
+
const HARNESS_FAILURE_MESSAGE_KEYS = ['result', 'error_message', 'message', 'text'];
|
|
26361
|
+
/**
|
|
26362
|
+
* Patterns which extract one JSON string value reported under a harness failure message key.
|
|
26363
|
+
*/
|
|
26364
|
+
const HARNESS_FAILURE_MESSAGE_PATTERNS = HARNESS_FAILURE_MESSAGE_KEYS.map((messageKey) => new RegExp(`"${messageKey}"\\s*:\\s*("(?:[^"\\\\]|\\\\.)*")`, 'g'));
|
|
26365
|
+
/**
|
|
26366
|
+
* Signatures which mean that the harness refused to work because it is not logged in.
|
|
26367
|
+
*
|
|
26368
|
+
* They are deliberately narrow phrases instead of single words like `login`, because the output of a harness
|
|
26369
|
+
* routinely mentions its own `/login` command among the commands it offers, and such a mention must never be
|
|
26370
|
+
* read as a failed login.
|
|
26371
|
+
*/
|
|
26372
|
+
const AUTHENTICATION_FAILURE_PATTERNS = [
|
|
26373
|
+
/\bauthentication[ _-]?failed\b/i,
|
|
26374
|
+
/\bfailed to authenticate\b/i,
|
|
26375
|
+
/\bnot authenticated\b/i,
|
|
26376
|
+
/\bnot logged[ -]?in\b/i,
|
|
26377
|
+
/\bnot signed[ -]?in\b/i,
|
|
26378
|
+
/\bno authentication information found\b/i,
|
|
26379
|
+
/\bauthentication (?:is )?required\b/i,
|
|
26380
|
+
/\blogin (?:is )?required\b/i,
|
|
26381
|
+
/\bplease (?:log|sign) in\b/i,
|
|
26382
|
+
/\bunauthorized\b/i,
|
|
26383
|
+
/\b(?:oauth|session|token|credentials?|login)\b[^.]{0,60}?\bexpired\b/i,
|
|
26384
|
+
/\bexpired\b[^.]{0,60}?\b(?:oauth|session|token|credentials?|login)\b/i,
|
|
26385
|
+
/\binvalid api[ _-]?key\b/i,
|
|
26386
|
+
/\bmissing api[ _-]?key\b/i,
|
|
26387
|
+
/\binvalid credentials?\b/i,
|
|
26388
|
+
];
|
|
26389
|
+
/**
|
|
26390
|
+
* Reads the reason why a harness refused to work because it is not logged in, from its raw CLI output.
|
|
26391
|
+
*
|
|
26392
|
+
* Messages the harness reports in machine-readable output are preferred over its raw output lines, so the
|
|
26393
|
+
* reason is the sentence the harness wrote for a human and not the JSON event which transported it.
|
|
26394
|
+
*
|
|
26395
|
+
* @returns One short single-line reason, or `undefined` when the failure was not caused by authentication.
|
|
26396
|
+
*/
|
|
26397
|
+
function extractHarnessAuthenticationFailureReason(harnessOutput) {
|
|
26398
|
+
const reportedMessages = [...extractHarnessReportedMessages(harnessOutput), ...harnessOutput.split(/\r?\n/)];
|
|
26399
|
+
for (const reportedMessage of reportedMessages) {
|
|
26400
|
+
const reason = reportedMessage.replace(/\s+/g, ' ').trim();
|
|
26401
|
+
if (isAuthenticationFailureReason(reason)) {
|
|
26402
|
+
return limitAuthenticationFailureReason(reason);
|
|
26403
|
+
}
|
|
26404
|
+
}
|
|
26405
|
+
return undefined;
|
|
26406
|
+
}
|
|
26407
|
+
/**
|
|
26408
|
+
* Lists the human-readable messages a harness reported in its machine-readable output.
|
|
26409
|
+
*/
|
|
26410
|
+
function extractHarnessReportedMessages(harnessOutput) {
|
|
26411
|
+
const reportedMessages = [];
|
|
26412
|
+
for (const messagePattern of HARNESS_FAILURE_MESSAGE_PATTERNS) {
|
|
26413
|
+
for (const match of harnessOutput.matchAll(messagePattern)) {
|
|
26414
|
+
const reportedMessage = parseSerializedJsonString(match[1]);
|
|
26415
|
+
if (reportedMessage !== undefined) {
|
|
26416
|
+
reportedMessages.push(reportedMessage);
|
|
26417
|
+
}
|
|
26418
|
+
}
|
|
26419
|
+
}
|
|
26420
|
+
return reportedMessages;
|
|
26421
|
+
}
|
|
26422
|
+
/**
|
|
26423
|
+
* Reads one JSON string literal back into plain text, tolerating output which only looks like JSON.
|
|
26424
|
+
*/
|
|
26425
|
+
function parseSerializedJsonString(serializedString) {
|
|
26426
|
+
if (serializedString === undefined) {
|
|
26427
|
+
return undefined;
|
|
26428
|
+
}
|
|
26429
|
+
try {
|
|
26430
|
+
const parsedString = JSON.parse(serializedString);
|
|
26431
|
+
return typeof parsedString === 'string' ? parsedString : undefined;
|
|
26432
|
+
}
|
|
26433
|
+
catch (_a) {
|
|
26434
|
+
return undefined;
|
|
26435
|
+
}
|
|
26436
|
+
}
|
|
26437
|
+
/**
|
|
26438
|
+
* Returns true when one message of the harness says that it is not logged in.
|
|
26439
|
+
*/
|
|
26440
|
+
function isAuthenticationFailureReason(reportedMessage) {
|
|
26441
|
+
return AUTHENTICATION_FAILURE_PATTERNS.some((pattern) => pattern.test(reportedMessage));
|
|
26442
|
+
}
|
|
26443
|
+
/**
|
|
26444
|
+
* Shortens a very long reason, so the guidance which follows it stays visible in the terminal.
|
|
26445
|
+
*/
|
|
26446
|
+
function limitAuthenticationFailureReason(reason) {
|
|
26447
|
+
if (reason.length <= MAXIMUM_AUTHENTICATION_FAILURE_REASON_LENGTH) {
|
|
26448
|
+
return reason;
|
|
26449
|
+
}
|
|
26450
|
+
return `${reason.slice(0, MAXIMUM_AUTHENTICATION_FAILURE_REASON_LENGTH)}...`;
|
|
26451
|
+
}
|
|
26452
|
+
|
|
26453
|
+
/**
|
|
26454
|
+
* Wraps one prompt runner so a failure caused by a missing or expired harness login is reported as a branded
|
|
26455
|
+
* `AuthenticationError` which tells the user how to sign in again.
|
|
26456
|
+
*
|
|
26457
|
+
* Each harness reports its own failures differently, but all of them report them by failing `runPrompt` with
|
|
26458
|
+
* the raw CLI output as the message. Translating the failure here therefore keeps exactly one place which has
|
|
26459
|
+
* to recognize an unauthenticated harness, for every harness and for every command which runs prompts.
|
|
26460
|
+
*/
|
|
26461
|
+
function createAuthenticationAwarePromptRunner(runner, harnessName) {
|
|
26462
|
+
var _a;
|
|
26463
|
+
return {
|
|
26464
|
+
name: runner.name,
|
|
26465
|
+
runPrompt: async (options) => {
|
|
26466
|
+
try {
|
|
26467
|
+
return await runner.runPrompt(options);
|
|
26468
|
+
}
|
|
26469
|
+
catch (error) {
|
|
26470
|
+
const reason = extractHarnessAuthenticationFailureReason(formatUnknownErrorMessage(error));
|
|
26471
|
+
if (reason === undefined) {
|
|
26472
|
+
throw error;
|
|
26473
|
+
}
|
|
26474
|
+
throw buildHarnessAuthenticationError({ harnessName, reason });
|
|
26475
|
+
}
|
|
26476
|
+
},
|
|
26477
|
+
getSubscriptionUsage: (_a = runner.getSubscriptionUsage) === null || _a === void 0 ? void 0 : _a.bind(runner),
|
|
26478
|
+
};
|
|
26479
|
+
}
|
|
26480
|
+
|
|
26233
26481
|
/**
|
|
26234
26482
|
* Creates a temporary script file, runs it, and cleans it up unless preservation is requested or the run fails.
|
|
26235
26483
|
*/
|
|
@@ -27969,6 +28217,18 @@
|
|
|
27969
28217
|
if (!agentName) {
|
|
27970
28218
|
throw new Error('Missing --harness in non-dry run mode');
|
|
27971
28219
|
}
|
|
28220
|
+
const resolution = resolveHarnessPromptRunner(agentName, options);
|
|
28221
|
+
return {
|
|
28222
|
+
...resolution,
|
|
28223
|
+
// Note: Every harness is wrapped here, so a harness which is not logged in is reported the same clear
|
|
28224
|
+
// way no matter which harness it is and which command has resolved the runner
|
|
28225
|
+
runner: createAuthenticationAwarePromptRunner(resolution.runner, agentName),
|
|
28226
|
+
};
|
|
28227
|
+
}
|
|
28228
|
+
/**
|
|
28229
|
+
* Creates the runner of one selected harness together with its status-line metadata.
|
|
28230
|
+
*/
|
|
28231
|
+
function resolveHarnessPromptRunner(agentName, options) {
|
|
27972
28232
|
if (agentName === 'openai-codex') {
|
|
27973
28233
|
return createOpenAiCodexRunnerResolution(options);
|
|
27974
28234
|
}
|
|
@@ -28436,11 +28696,19 @@
|
|
|
28436
28696
|
* Maximum width used for the rich coder-run frame.
|
|
28437
28697
|
*/
|
|
28438
28698
|
const MAX_FRAME_WIDTH = 96;
|
|
28699
|
+
/**
|
|
28700
|
+
* Number of terminal columns deliberately left unused by the rich coder-run frame.
|
|
28701
|
+
*
|
|
28702
|
+
* A row which fills the final physical terminal column can auto-wrap. The incremental terminal
|
|
28703
|
+
* updater moves by logical rows, so an auto-wrapped row would put its cursor out of sync with the
|
|
28704
|
+
* frame and let a later animated avatar redraw overwrite dashboard content.
|
|
28705
|
+
*/
|
|
28706
|
+
const TERMINAL_AUTO_WRAP_RESERVED_COLUMNS = 1;
|
|
28439
28707
|
/**
|
|
28440
28708
|
* Builds the complete boxed terminal frame for the rich `ptbk coder run` UI.
|
|
28441
28709
|
*/
|
|
28442
28710
|
function buildCoderRunUiFrame(options) {
|
|
28443
|
-
const totalWidth =
|
|
28711
|
+
const totalWidth = resolveCoderRunUiFrameWidth(options.terminalWidth);
|
|
28444
28712
|
const isPromptActive = options.phase === 'running' || options.phase === 'verifying' || options.phase === 'loading';
|
|
28445
28713
|
const promptStatusPrefix = isPromptActive ? `${colors__default["default"].yellow(`${options.spinner} `)}` : '';
|
|
28446
28714
|
const pausePresentation = buildPausePresentation(options.phase, options.pauseState, options.pauseTargetLabel, options.statusMessage);
|
|
@@ -28477,6 +28745,16 @@
|
|
|
28477
28745
|
frame.push(...renderBox('Controls', controlsBoxLines, totalWidth, colors__default["default"].white.bold));
|
|
28478
28746
|
return frame;
|
|
28479
28747
|
}
|
|
28748
|
+
/**
|
|
28749
|
+
* Resolves the safe width of the rich terminal frame from the available physical terminal columns.
|
|
28750
|
+
*
|
|
28751
|
+
* The reserved trailing column keeps every boxed row from auto-wrapping, which makes the frame's
|
|
28752
|
+
* logical row count match its physical terminal row count during animated incremental redraws.
|
|
28753
|
+
*/
|
|
28754
|
+
function resolveCoderRunUiFrameWidth(terminalWidth) {
|
|
28755
|
+
const availableFrameWidth = terminalWidth - TERMINAL_AUTO_WRAP_RESERVED_COLUMNS;
|
|
28756
|
+
return Math.max(MIN_FRAME_WIDTH, Math.min(availableFrameWidth, MAX_FRAME_WIDTH));
|
|
28757
|
+
}
|
|
28480
28758
|
/**
|
|
28481
28759
|
* Builds the header visual above the dashboard boxes.
|
|
28482
28760
|
*
|
|
@@ -29953,16 +30231,14 @@
|
|
|
29953
30231
|
*/
|
|
29954
30232
|
const DEFAULT_TERMINAL_WIDTH = 80;
|
|
29955
30233
|
/**
|
|
29956
|
-
*
|
|
29957
|
-
|
|
29958
|
-
|
|
29959
|
-
/**
|
|
29960
|
-
* Returns the usable terminal width, capped at 96.
|
|
30234
|
+
* Returns the number of columns reported by the current terminal.
|
|
30235
|
+
*
|
|
30236
|
+
* The frame builder owns clamping and reserves its trailing auto-wrap safety column.
|
|
29961
30237
|
*
|
|
29962
30238
|
* @private internal utility of coder run UI
|
|
29963
30239
|
*/
|
|
29964
|
-
function
|
|
29965
|
-
return
|
|
30240
|
+
function getTerminalColumnCount() {
|
|
30241
|
+
return process.stdout.columns || DEFAULT_TERMINAL_WIDTH;
|
|
29966
30242
|
}
|
|
29967
30243
|
/**
|
|
29968
30244
|
* Boots the ANSI terminal UI for `ptbk coder run`.
|
|
@@ -30069,7 +30345,7 @@
|
|
|
30069
30345
|
*/
|
|
30070
30346
|
function buildFrameLines() {
|
|
30071
30347
|
return buildFrameLinesFromState({
|
|
30072
|
-
terminalWidth:
|
|
30348
|
+
terminalWidth: getTerminalColumnCount(),
|
|
30073
30349
|
animationFrame: spinnerFrame,
|
|
30074
30350
|
animationTimeMs: Date.now() - animationStartTimeMs,
|
|
30075
30351
|
spinner: SPINNER_FRAMES[spinnerFrame],
|
|
@@ -33800,19 +34076,6 @@
|
|
|
33800
34076
|
}
|
|
33801
34077
|
}
|
|
33802
34078
|
|
|
33803
|
-
/**
|
|
33804
|
-
* AuthenticationError is thrown from login function which is dependency of remote server
|
|
33805
|
-
*
|
|
33806
|
-
* @public exported from `@promptbook/core`
|
|
33807
|
-
*/
|
|
33808
|
-
class AuthenticationError extends Error {
|
|
33809
|
-
constructor(message) {
|
|
33810
|
-
super(message);
|
|
33811
|
-
this.name = 'AuthenticationError';
|
|
33812
|
-
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
33813
|
-
}
|
|
33814
|
-
}
|
|
33815
|
-
|
|
33816
34079
|
/**
|
|
33817
34080
|
* This error indicates that the pipeline collection cannot be properly loaded
|
|
33818
34081
|
*
|
|
@@ -42041,11 +42304,7 @@
|
|
|
42041
42304
|
$initializeAgentsServerDevCommand(agentsServerCommand);
|
|
42042
42305
|
$initializeAgentsServerInitCommand(agentsServerCommand);
|
|
42043
42306
|
$initializeAgentsServerStartCommand(agentsServerCommand);
|
|
42044
|
-
agentsServerCommand
|
|
42045
|
-
console.info(colors__default["default"].yellow('Please specify a subcommand.'));
|
|
42046
|
-
console.info('');
|
|
42047
|
-
agentsServerCommand.help();
|
|
42048
|
-
});
|
|
42307
|
+
$requireCliSubcommand(agentsServerCommand);
|
|
42049
42308
|
}
|
|
42050
42309
|
// Note: [🟡] Code for CLI command [agents-server](src/cli/cli-commands/agents-server.ts) should never be published outside of `@promptbook/cli`
|
|
42051
42310
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -42135,6 +42394,58 @@
|
|
|
42135
42394
|
// Note: [🟡] Code for CLI git synchronization options [coderGitSyncCliOptions](src/cli/cli-commands/common/coderGitSyncCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
42136
42395
|
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
42137
42396
|
|
|
42397
|
+
/**
|
|
42398
|
+
* Description block shared by the `ptbk coder` commands which can ask interactive questions.
|
|
42399
|
+
*
|
|
42400
|
+
* @private internal utility of `promptbookCli`
|
|
42401
|
+
*/
|
|
42402
|
+
const QUESTIONS_DESCRIPTION = _spaceTrim.spaceTrim(`
|
|
42403
|
+
Interactive questions:
|
|
42404
|
+
- Steps which need an answer to continue are asked in the terminal
|
|
42405
|
+
- --no-questions never asks: an optional step is skipped with a note how to do it manually, a required one fails right away
|
|
42406
|
+
`);
|
|
42407
|
+
/**
|
|
42408
|
+
* Registers the shared `--no-questions` option on a `ptbk coder` command which can ask interactive questions.
|
|
42409
|
+
*
|
|
42410
|
+
* @private internal utility of `promptbookCli`
|
|
42411
|
+
*/
|
|
42412
|
+
function addQuestionsOption(command) {
|
|
42413
|
+
command.option('--no-questions', 'Never ask an interactive question and skip every optional step which needs an answer to continue');
|
|
42414
|
+
}
|
|
42415
|
+
/**
|
|
42416
|
+
* Converts the Commander questions flag into the normalized interactive-questions option.
|
|
42417
|
+
*
|
|
42418
|
+
* @private internal utility of `promptbookCli`
|
|
42419
|
+
*/
|
|
42420
|
+
function normalizeQuestionsCliOptions(cliOptions) {
|
|
42421
|
+
return {
|
|
42422
|
+
isAskingQuestionsEnabled: cliOptions.questions,
|
|
42423
|
+
};
|
|
42424
|
+
}
|
|
42425
|
+
/**
|
|
42426
|
+
* Asserts that a command which waits for a user confirmation before each prompt is allowed to ask for it.
|
|
42427
|
+
*
|
|
42428
|
+
* @throws {NotAllowed} when `--no-auto` is combined with `--no-questions`
|
|
42429
|
+
* @private internal utility of `promptbookCli`
|
|
42430
|
+
*/
|
|
42431
|
+
function assertUserConfirmationIsAllowed(options) {
|
|
42432
|
+
const { isAskingQuestionsEnabled, isWaitingForUser } = options;
|
|
42433
|
+
if (!isWaitingForUser || isAskingQuestionsEnabled) {
|
|
42434
|
+
return;
|
|
42435
|
+
}
|
|
42436
|
+
throw new NotAllowed(_spaceTrim.spaceTrim(`
|
|
42437
|
+
Flag \`--no-auto\` can not be used together with \`--no-questions\`.
|
|
42438
|
+
|
|
42439
|
+
**There is nobody who could confirm each prompt when no question may be asked.**
|
|
42440
|
+
|
|
42441
|
+
Actionable hints:
|
|
42442
|
+
- Keep \`--no-auto\` for a supervised run, for example \`ptbk coder run --harness claude-code --no-auto\`.
|
|
42443
|
+
- Keep \`--no-questions\` for an unattended run, for example \`ptbk coder run --harness claude-code --no-questions\`.
|
|
42444
|
+
`));
|
|
42445
|
+
}
|
|
42446
|
+
// Note: [🟡] Code for CLI interactive questions options [questionsCliOptions](src/cli/cli-commands/common/questionsCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
42447
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
42448
|
+
|
|
42138
42449
|
/**
|
|
42139
42450
|
* Relative path to the root prompts directory used by Promptbook coder utilities.
|
|
42140
42451
|
*
|
|
@@ -42153,6 +42464,12 @@
|
|
|
42153
42464
|
* @private internal utility of `ptbk coder`
|
|
42154
42465
|
*/
|
|
42155
42466
|
const PROMPTS_TEMPLATES_DIRECTORY_PATH = path.join(PROMPTS_DIRECTORY_PATH$1, 'templates');
|
|
42467
|
+
/**
|
|
42468
|
+
* Relative path to the project-agnostic `common` boilerplate template referenced by the default coder scripts.
|
|
42469
|
+
*
|
|
42470
|
+
* @private internal utility of `ptbk coder`
|
|
42471
|
+
*/
|
|
42472
|
+
const COMMON_PROMPT_TEMPLATE_FILE_PATH = path.join(PROMPTS_TEMPLATES_DIRECTORY_PATH, 'common.md');
|
|
42156
42473
|
/**
|
|
42157
42474
|
* Built-in boilerplate templates available to `coder generate-boilerplates`.
|
|
42158
42475
|
*
|
|
@@ -42161,7 +42478,7 @@
|
|
|
42161
42478
|
const DEFAULT_CODER_PROMPT_TEMPLATE_DEFINITIONS = [
|
|
42162
42479
|
{
|
|
42163
42480
|
id: 'common',
|
|
42164
|
-
relativeFilePath:
|
|
42481
|
+
relativeFilePath: COMMON_PROMPT_TEMPLATE_FILE_PATH,
|
|
42165
42482
|
slugPrefix: null,
|
|
42166
42483
|
content: _spaceTrim.spaceTrim(`
|
|
42167
42484
|
- @@@
|
|
@@ -42207,30 +42524,17 @@
|
|
|
42207
42524
|
return definition;
|
|
42208
42525
|
}
|
|
42209
42526
|
/**
|
|
42210
|
-
* Ensures
|
|
42527
|
+
* Ensures one project-owned coder template file exists without overwriting user customizations.
|
|
42211
42528
|
*
|
|
42212
42529
|
* @private internal utility of `ptbk coder`
|
|
42213
42530
|
*/
|
|
42214
|
-
async function
|
|
42215
|
-
const
|
|
42216
|
-
|
|
42217
|
-
|
|
42218
|
-
if (await isExistingFile$3(absoluteTemplatePath)) {
|
|
42219
|
-
ensuredTemplateFiles.push({
|
|
42220
|
-
id: definition.id,
|
|
42221
|
-
relativeFilePath: definition.relativeFilePath,
|
|
42222
|
-
status: 'unchanged',
|
|
42223
|
-
});
|
|
42224
|
-
continue;
|
|
42225
|
-
}
|
|
42226
|
-
await promises.writeFile(absoluteTemplatePath, `${definition.content}\n`, 'utf-8');
|
|
42227
|
-
ensuredTemplateFiles.push({
|
|
42228
|
-
id: definition.id,
|
|
42229
|
-
relativeFilePath: definition.relativeFilePath,
|
|
42230
|
-
status: 'created',
|
|
42231
|
-
});
|
|
42531
|
+
async function ensureDefaultCoderPromptTemplateFile(projectPath, definition) {
|
|
42532
|
+
const absoluteTemplatePath = path.join(projectPath, definition.relativeFilePath);
|
|
42533
|
+
if (await isExistingFile$3(absoluteTemplatePath)) {
|
|
42534
|
+
return 'unchanged';
|
|
42232
42535
|
}
|
|
42233
|
-
|
|
42536
|
+
await promises.writeFile(absoluteTemplatePath, `${definition.content}\n`, 'utf-8');
|
|
42537
|
+
return 'created';
|
|
42234
42538
|
}
|
|
42235
42539
|
/**
|
|
42236
42540
|
* Resolves the template requested by `coder generate-boilerplates`.
|
|
@@ -42386,6 +42690,8 @@
|
|
|
42386
42690
|
- \`ptbk coder add\`
|
|
42387
42691
|
|
|
42388
42692
|
${block(CODER_GIT_SYNC_DESCRIPTION)}
|
|
42693
|
+
|
|
42694
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
42389
42695
|
`));
|
|
42390
42696
|
command.argument('[description]', 'Plain-language description of the feature or task to implement');
|
|
42391
42697
|
command.option('--priority <priority>', 'Priority of the new prompt — higher priorities run first (rendered as trailing `!` markers)', parsePriorityOption, 0);
|
|
@@ -42397,11 +42703,13 @@
|
|
|
42397
42703
|
.join(', ')}) or a markdown file path relative to the current project root.
|
|
42398
42704
|
`));
|
|
42399
42705
|
addCoderGitSyncOptions(command);
|
|
42706
|
+
addQuestionsOption(command);
|
|
42400
42707
|
command.action(handleActionErrors(async (descriptionArgument, cliOptions) => {
|
|
42401
42708
|
const { priority, template: templateOption } = cliOptions;
|
|
42402
42709
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
42710
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
42403
42711
|
const projectPath = process.cwd();
|
|
42404
|
-
const description = await resolveCoderPromptDescription(descriptionArgument);
|
|
42712
|
+
const description = await resolveCoderPromptDescription(descriptionArgument, questionsOptions);
|
|
42405
42713
|
// Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
|
|
42406
42714
|
const { $commitCoderChanges, $startCoderGitSync } = await Promise.resolve().then(function () { return coderGitSync; });
|
|
42407
42715
|
const commitScope = await $startCoderGitSync({ gitSync, projectPath });
|
|
@@ -42471,7 +42779,7 @@
|
|
|
42471
42779
|
*
|
|
42472
42780
|
* @private internal utility of `coder add` command
|
|
42473
42781
|
*/
|
|
42474
|
-
async function resolveCoderPromptDescription(descriptionArgument) {
|
|
42782
|
+
async function resolveCoderPromptDescription(descriptionArgument, { isAskingQuestionsEnabled }) {
|
|
42475
42783
|
if (descriptionArgument !== undefined && descriptionArgument.trim() !== '') {
|
|
42476
42784
|
return descriptionArgument.trim();
|
|
42477
42785
|
}
|
|
@@ -42489,6 +42797,14 @@
|
|
|
42489
42797
|
}
|
|
42490
42798
|
return standardInputDescription;
|
|
42491
42799
|
}
|
|
42800
|
+
if (!isAskingQuestionsEnabled) {
|
|
42801
|
+
throw new ParseError(_spaceTrim.spaceTrim(`
|
|
42802
|
+
Cannot add a prompt without a description.
|
|
42803
|
+
|
|
42804
|
+
The description can not be typed interactively because \`--no-questions\` is used — provide it as an argument or pipe it through stdin instead:
|
|
42805
|
+
- \`ptbk coder add --no-questions "some new feature"\`
|
|
42806
|
+
`));
|
|
42807
|
+
}
|
|
42492
42808
|
const { default: prompts } = await loadPromptsModule();
|
|
42493
42809
|
const response = await prompts({
|
|
42494
42810
|
type: 'text',
|
|
@@ -43139,10 +43455,15 @@
|
|
|
43139
43455
|
*
|
|
43140
43456
|
* Note: `$` is used to indicate that this function is not a pure function - it reads the answer from stdin.
|
|
43141
43457
|
*
|
|
43142
|
-
* @returns `true` when the user confirms, `false` when the user declines
|
|
43458
|
+
* @returns `true` when the user confirms, `false` when the user declines, the terminal is not interactive
|
|
43459
|
+
* or the questions are disabled by `--no-questions`.
|
|
43143
43460
|
* @private internal utility of `promptbookCli`
|
|
43144
43461
|
*/
|
|
43145
|
-
async function $askForConfirmation(question) {
|
|
43462
|
+
async function $askForConfirmation(question, { isAskingQuestionsEnabled }) {
|
|
43463
|
+
if (!isAskingQuestionsEnabled) {
|
|
43464
|
+
// Note: `--no-questions` forbids asking, so the optional change is declined without blocking the run.
|
|
43465
|
+
return false;
|
|
43466
|
+
}
|
|
43146
43467
|
if (!process.stdin.isTTY) {
|
|
43147
43468
|
// Note: In non-interactive environments like CI there is nobody who could confirm the change.
|
|
43148
43469
|
return false;
|
|
@@ -43165,11 +43486,12 @@
|
|
|
43165
43486
|
*
|
|
43166
43487
|
* Note: `$` is used to indicate that this function is not a pure function - it reads the answer from stdin
|
|
43167
43488
|
*
|
|
43168
|
-
* @returns `true` when the user confirms, `false` when the user declines
|
|
43489
|
+
* @returns `true` when the user confirms, `false` when the user declines, the terminal is not interactive
|
|
43490
|
+
* or the questions are disabled by `--no-questions`
|
|
43169
43491
|
* @private internal utility of `promptbookCli`
|
|
43170
43492
|
*/
|
|
43171
|
-
async function $askForNpmPackageInstallationApproval(question) {
|
|
43172
|
-
return $askForConfirmation(question);
|
|
43493
|
+
async function $askForNpmPackageInstallationApproval(question, questionsOptions) {
|
|
43494
|
+
return $askForConfirmation(question, questionsOptions);
|
|
43173
43495
|
}
|
|
43174
43496
|
// 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`
|
|
43175
43497
|
|
|
@@ -43359,7 +43681,7 @@
|
|
|
43359
43681
|
*
|
|
43360
43682
|
* @private internal utility of `promptbookCli`
|
|
43361
43683
|
*/
|
|
43362
|
-
async function $applyHarnessInstallationStatus(status) {
|
|
43684
|
+
async function $applyHarnessInstallationStatus(status, questionsOptions) {
|
|
43363
43685
|
const { definition, installationState, installedVersion } = status;
|
|
43364
43686
|
if (installationState === 'up-to-date') {
|
|
43365
43687
|
console.info(colors__default["default"].gray(`✔ ${definition.label} ${installedVersion} is up to date.`));
|
|
@@ -43375,17 +43697,17 @@
|
|
|
43375
43697
|
}
|
|
43376
43698
|
console.warn(colors__default["default"].yellow(formatHarnessInstallationWarning(status)));
|
|
43377
43699
|
if (installationState === 'not-installed') {
|
|
43378
|
-
await $applyMissingHarnessInstallation(definition);
|
|
43700
|
+
await $applyMissingHarnessInstallation(definition, questionsOptions);
|
|
43379
43701
|
return;
|
|
43380
43702
|
}
|
|
43381
|
-
await $applyOutdatedHarnessInstallation(status);
|
|
43703
|
+
await $applyOutdatedHarnessInstallation(status, questionsOptions);
|
|
43382
43704
|
}
|
|
43383
43705
|
/**
|
|
43384
43706
|
* Offers to install a missing harness globally through npm.
|
|
43385
43707
|
*/
|
|
43386
|
-
async function $applyMissingHarnessInstallation(definition) {
|
|
43708
|
+
async function $applyMissingHarnessInstallation(definition, questionsOptions) {
|
|
43387
43709
|
const installCommand = buildHarnessInstallCommand(definition);
|
|
43388
|
-
const isInstallationApproved = await $askForNpmPackageInstallationApproval(`Install ${definition.label} globally now
|
|
43710
|
+
const isInstallationApproved = await $askForNpmPackageInstallationApproval(`Install ${definition.label} globally now?`, questionsOptions);
|
|
43389
43711
|
if (!isInstallationApproved) {
|
|
43390
43712
|
console.info(colors__default["default"].gray(`Skipped, run \`${installCommand}\` to do it manually.`));
|
|
43391
43713
|
return;
|
|
@@ -43400,14 +43722,14 @@
|
|
|
43400
43722
|
/**
|
|
43401
43723
|
* Offers to update an outdated harness exactly where it is installed.
|
|
43402
43724
|
*/
|
|
43403
|
-
async function $applyOutdatedHarnessInstallation(status) {
|
|
43725
|
+
async function $applyOutdatedHarnessInstallation(status, questionsOptions) {
|
|
43404
43726
|
const { definition, latestVersion, installationOrigin } = status;
|
|
43405
43727
|
const updatePlan = resolveHarnessUpdatePlan(definition, installationOrigin.installationMethod);
|
|
43406
43728
|
if (updatePlan.command === null || !updatePlan.isRunnableByPromptbook) {
|
|
43407
43729
|
console.info(colors__default["default"].gray(formatHarnessManualUpdateInstruction(status, updatePlan)));
|
|
43408
43730
|
return;
|
|
43409
43731
|
}
|
|
43410
|
-
const isUpdateApproved = await $askForNpmPackageInstallationApproval(`Update ${definition.label} to ${latestVersion} with \`${updatePlan.command}\` now
|
|
43732
|
+
const isUpdateApproved = await $askForNpmPackageInstallationApproval(`Update ${definition.label} to ${latestVersion} with \`${updatePlan.command}\` now?`, questionsOptions);
|
|
43411
43733
|
if (!isUpdateApproved) {
|
|
43412
43734
|
console.info(colors__default["default"].gray(`Skipped, run \`${updatePlan.command}\` to do it manually.`));
|
|
43413
43735
|
return;
|
|
@@ -43843,7 +44165,7 @@
|
|
|
43843
44165
|
// Note: [🟡] Code for CLI harness installation check [$checkHarnessInstallation](src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts) should never be published outside of `@promptbook/cli`
|
|
43844
44166
|
|
|
43845
44167
|
/**
|
|
43846
|
-
* Checks that every given CLI coding harness is installed globally and, when enabled, up to date.
|
|
44168
|
+
* Checks that every given CLI coding harness is installed globally and, when the questions are enabled, up to date.
|
|
43847
44169
|
* Offers to install missing harnesses and update outdated ones.
|
|
43848
44170
|
*
|
|
43849
44171
|
* Harness names which are `undefined`, for example when no `--harness` is selected in a dry run,
|
|
@@ -43853,15 +44175,18 @@
|
|
|
43853
44175
|
*
|
|
43854
44176
|
* @private internal utility of `promptbookCli`
|
|
43855
44177
|
*/
|
|
43856
|
-
async function $ensureHarnessInstallations(harnessNames,
|
|
44178
|
+
async function $ensureHarnessInstallations(harnessNames, questionsOptions) {
|
|
43857
44179
|
const definitions = resolveCheckedHarnessDefinitions(harnessNames);
|
|
43858
44180
|
if (definitions.length === 0) {
|
|
43859
44181
|
return;
|
|
43860
44182
|
}
|
|
44183
|
+
// Note: An outdated harness can be updated only after the user confirms it, so `--no-questions`
|
|
44184
|
+
// skips the slower npm registry lookup entirely and only reports what is installed.
|
|
44185
|
+
const isHarnessUpdateCheckEnabled = questionsOptions.isAskingQuestionsEnabled;
|
|
43861
44186
|
// Note: Detection of all harnesses runs in parallel, the questions have to be asked one by one
|
|
43862
44187
|
const statuses = await Promise.all(definitions.map((definition) => $checkHarnessInstallation(definition, isHarnessUpdateCheckEnabled)));
|
|
43863
44188
|
for (const status of statuses) {
|
|
43864
|
-
await $applyHarnessInstallationStatus(status);
|
|
44189
|
+
await $applyHarnessInstallationStatus(status, questionsOptions);
|
|
43865
44190
|
}
|
|
43866
44191
|
}
|
|
43867
44192
|
/**
|
|
@@ -43873,48 +44198,6 @@
|
|
|
43873
44198
|
}
|
|
43874
44199
|
// Note: [🟡] Code for CLI harness installation orchestration [$ensureHarnessInstallations](src/cli/cli-commands/common/harness/$ensureHarnessInstallations.ts) should never be published outside of `@promptbook/cli`
|
|
43875
44200
|
|
|
43876
|
-
/**
|
|
43877
|
-
* Registers the shared `--no-harness-update` option on a `ptbk coder` command that uses a coding harness.
|
|
43878
|
-
*
|
|
43879
|
-
* @private internal utility of `promptbookCli`
|
|
43880
|
-
*/
|
|
43881
|
-
function addHarnessUpdateOption(command) {
|
|
43882
|
-
command.option('--no-harness-update', 'Skip checking whether the installed coding harnesses are up to date');
|
|
43883
|
-
}
|
|
43884
|
-
/**
|
|
43885
|
-
* Converts the Commander harness-update flag into the normalized harness-check option.
|
|
43886
|
-
*
|
|
43887
|
-
* @private internal utility of `promptbookCli`
|
|
43888
|
-
*/
|
|
43889
|
-
function normalizeHarnessUpdateCliOptions(cliOptions) {
|
|
43890
|
-
return {
|
|
43891
|
-
isHarnessUpdateCheckEnabled: cliOptions.harnessUpdate,
|
|
43892
|
-
};
|
|
43893
|
-
}
|
|
43894
|
-
// Note: [🟡] Code for CLI harness update options [harnessUpdateCliOptions](src/cli/cli-commands/common/harnessUpdateCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
43895
|
-
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
43896
|
-
|
|
43897
|
-
/**
|
|
43898
|
-
* Relative path to the Promptbook Coder quick-reference file initialized in project roots.
|
|
43899
|
-
*
|
|
43900
|
-
* @private internal utility of `ptbk coder`
|
|
43901
|
-
*/
|
|
43902
|
-
const AGENT_CODING_FILE_PATH = 'AGENT_CODING.md';
|
|
43903
|
-
/**
|
|
43904
|
-
* Returns the default coder `AGENT_CODING.md` quick-reference content.
|
|
43905
|
-
*
|
|
43906
|
-
* @private internal utility of `ptbk coder`
|
|
43907
|
-
*/
|
|
43908
|
-
function getDefaultCoderAgentCodingFileContent() {
|
|
43909
|
-
return _spaceTrim.spaceTrim(`
|
|
43910
|
-
# ✨ Promptbook Coder agent coding
|
|
43911
|
-
|
|
43912
|
-
This project is using [Promptbook Coder](https://coder.ptbk.io) or run \`ptbk coder\`!
|
|
43913
|
-
`);
|
|
43914
|
-
}
|
|
43915
|
-
// Note: [🟡] Code for coder AGENT_CODING file boilerplate [agentCodingFile](src/cli/cli-commands/coder/agentCodingFile.ts) should never be published outside of `@promptbook/cli`
|
|
43916
|
-
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
43917
|
-
|
|
43918
44201
|
/**
|
|
43919
44202
|
* Relative path to the shared coder context file initialized in project roots.
|
|
43920
44203
|
*
|
|
@@ -44016,6 +44299,51 @@
|
|
|
44016
44299
|
}
|
|
44017
44300
|
// Note: [🟡] Code for coder path formatting [formatDisplayPath](src/cli/cli-commands/coder/formatDisplayPath.ts) should never be published outside of `@promptbook/cli`
|
|
44018
44301
|
|
|
44302
|
+
/**
|
|
44303
|
+
* Creates the artifact definition of one project-owned coder prompt template.
|
|
44304
|
+
*/
|
|
44305
|
+
function createCoderPromptTemplateArtifactDefinition(definition) {
|
|
44306
|
+
return {
|
|
44307
|
+
relativeFilePath: definition.relativeFilePath,
|
|
44308
|
+
ensureArtifactFile: (projectPath) => ensureDefaultCoderPromptTemplateFile(projectPath, definition),
|
|
44309
|
+
};
|
|
44310
|
+
}
|
|
44311
|
+
/**
|
|
44312
|
+
* Every artifact which the default coder scripts can reference.
|
|
44313
|
+
*/
|
|
44314
|
+
const CODER_REFERENCED_ARTIFACT_DEFINITIONS = [
|
|
44315
|
+
{
|
|
44316
|
+
relativeFilePath: CODER_DEVELOPER_AGENT_FILE_PATH,
|
|
44317
|
+
ensureArtifactFile: ensureCoderDeveloperAgentFile,
|
|
44318
|
+
},
|
|
44319
|
+
{
|
|
44320
|
+
relativeFilePath: AGENTS_FILE_PATH,
|
|
44321
|
+
ensureArtifactFile: (projectPath) => ensureCoderMarkdownFile(projectPath, AGENTS_FILE_PATH, getDefaultCoderAgentsFileContent()),
|
|
44322
|
+
},
|
|
44323
|
+
...getDefaultCoderProjectPromptTemplateDefinitions().map(createCoderPromptTemplateArtifactDefinition),
|
|
44324
|
+
];
|
|
44325
|
+
/**
|
|
44326
|
+
* Creates only those referenced artifacts which the freshly added coder scripts point at.
|
|
44327
|
+
*
|
|
44328
|
+
* An artifact of a script which the project already defines is intentionally **not** created - the project-owned
|
|
44329
|
+
* script is kept as is, so it does not reference the default artifact in the first place.
|
|
44330
|
+
*
|
|
44331
|
+
* @private function of `initializeCoderProjectConfiguration`
|
|
44332
|
+
*/
|
|
44333
|
+
async function ensureCoderReferencedArtifacts(projectPath, referencedArtifactPaths) {
|
|
44334
|
+
const ensuredArtifacts = [];
|
|
44335
|
+
for (const { relativeFilePath, ensureArtifactFile } of CODER_REFERENCED_ARTIFACT_DEFINITIONS) {
|
|
44336
|
+
if (!referencedArtifactPaths.has(relativeFilePath)) {
|
|
44337
|
+
ensuredArtifacts.push({ relativeFilePath, status: 'not-referenced' });
|
|
44338
|
+
continue;
|
|
44339
|
+
}
|
|
44340
|
+
ensuredArtifacts.push({ relativeFilePath, status: await ensureArtifactFile(projectPath) });
|
|
44341
|
+
}
|
|
44342
|
+
return ensuredArtifacts;
|
|
44343
|
+
}
|
|
44344
|
+
// Note: [🟡] Code for coder init referenced artifacts [coderReferencedArtifacts](src/cli/cli-commands/coder/coderReferencedArtifacts.ts) should never be published outside of `@promptbook/cli`
|
|
44345
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44346
|
+
|
|
44019
44347
|
/**
|
|
44020
44348
|
* Fallback `.env` content used when no required variables need to be appended.
|
|
44021
44349
|
*/
|
|
@@ -44110,26 +44438,79 @@
|
|
|
44110
44438
|
}
|
|
44111
44439
|
// Note: [🟡] Code for coder init gitignore bootstrapping [ensureCoderGitignoreFile](src/cli/cli-commands/coder/ensureCoderGitignoreFile.ts) should never be published outside of `@promptbook/cli`
|
|
44112
44440
|
|
|
44441
|
+
/**
|
|
44442
|
+
* Name of the npm script which `ptbk coder run` uses to verify the project.
|
|
44443
|
+
*/
|
|
44444
|
+
const CODER_TEST_SCRIPT_NAME = 'test-for-ptbk-coder';
|
|
44113
44445
|
/**
|
|
44114
44446
|
* Default npm scripts initialized by `ptbk coder init`.
|
|
44447
|
+
*
|
|
44448
|
+
* Note: Using NPX because `ptbk` can be installed globally or locally, and NPX will resolve it correctly in either case.
|
|
44115
44449
|
*/
|
|
44116
|
-
const
|
|
44117
|
-
|
|
44118
|
-
|
|
44119
|
-
|
|
44120
|
-
|
|
44121
|
-
|
|
44122
|
-
|
|
44123
|
-
|
|
44450
|
+
const DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS = [
|
|
44451
|
+
{
|
|
44452
|
+
scriptName: 'coder:generate-boilerplates',
|
|
44453
|
+
scriptCommand: `npx ptbk coder generate-boilerplates --count ${DEFAULT_BOILERPLATE_COUNT_OPTION_VALUE} --template ${formatCoderScriptFilePath(COMMON_PROMPT_TEMPLATE_FILE_PATH)}`,
|
|
44454
|
+
referencedArtifactPaths: [COMMON_PROMPT_TEMPLATE_FILE_PATH],
|
|
44455
|
+
},
|
|
44456
|
+
{
|
|
44457
|
+
scriptName: 'coder:add',
|
|
44458
|
+
scriptCommand: `npx ptbk coder add --template ${formatCoderScriptFilePath(COMMON_PROMPT_TEMPLATE_FILE_PATH)}`,
|
|
44459
|
+
referencedArtifactPaths: [COMMON_PROMPT_TEMPLATE_FILE_PATH],
|
|
44460
|
+
},
|
|
44461
|
+
{
|
|
44462
|
+
scriptName: 'coder:run',
|
|
44463
|
+
scriptCommand: [
|
|
44464
|
+
'npx ptbk coder run --harness openai-codex --model gpt-5.6-terra --thinking-level max',
|
|
44465
|
+
`--agent ${formatDisplayPath(CODER_DEVELOPER_AGENT_FILE_PATH)}`,
|
|
44466
|
+
`--context ${formatDisplayPath(AGENTS_FILE_PATH)}`,
|
|
44467
|
+
`--test "npm run ${CODER_TEST_SCRIPT_NAME}" --test-before yes-and-fix`,
|
|
44468
|
+
].join(' '),
|
|
44469
|
+
referencedArtifactPaths: [CODER_DEVELOPER_AGENT_FILE_PATH, AGENTS_FILE_PATH],
|
|
44470
|
+
},
|
|
44471
|
+
// { scriptName: 'coder:find-refactor-candidates', scriptCommand: 'npx ptbk coder find-refactor-candidates', referencedArtifactPaths: [] },
|
|
44472
|
+
{
|
|
44473
|
+
scriptName: 'coder:verify',
|
|
44474
|
+
scriptCommand: 'npx ptbk coder verify',
|
|
44475
|
+
referencedArtifactPaths: [],
|
|
44476
|
+
},
|
|
44477
|
+
{
|
|
44478
|
+
// Note: The verification command of `coder:run` is a project-owned script, so every project can decide
|
|
44479
|
+
// what "verified" means without touching the `coder:run` script itself
|
|
44480
|
+
scriptName: CODER_TEST_SCRIPT_NAME,
|
|
44481
|
+
scriptCommand: 'npm test',
|
|
44482
|
+
referencedArtifactPaths: [],
|
|
44483
|
+
},
|
|
44484
|
+
];
|
|
44124
44485
|
/**
|
|
44125
44486
|
* Lists the default npm scripts initialized by `ptbk coder init`.
|
|
44126
44487
|
*
|
|
44127
44488
|
* @private internal utility of `coder init` command
|
|
44128
44489
|
*/
|
|
44129
44490
|
function getDefaultCoderPackageJsonScripts() {
|
|
44130
|
-
return
|
|
44491
|
+
return Object.fromEntries(DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS.map(({ scriptName, scriptCommand }) => [
|
|
44492
|
+
scriptName,
|
|
44493
|
+
scriptCommand,
|
|
44494
|
+
]));
|
|
44495
|
+
}
|
|
44496
|
+
/**
|
|
44497
|
+
* Collects the project-relative artifact paths referenced by the given default coder scripts.
|
|
44498
|
+
*
|
|
44499
|
+
* @private internal utility of `coder init` command
|
|
44500
|
+
*/
|
|
44501
|
+
function resolveCoderPackageJsonScriptReferencedArtifactPaths(scriptNames) {
|
|
44502
|
+
return new Set(DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS.filter(({ scriptName }) => scriptNames.includes(scriptName))
|
|
44503
|
+
.map(({ referencedArtifactPaths }) => referencedArtifactPaths)
|
|
44504
|
+
.flat());
|
|
44505
|
+
}
|
|
44506
|
+
/**
|
|
44507
|
+
* Formats one project-relative path as an explicitly project-rooted path usable inside a shell command.
|
|
44508
|
+
*/
|
|
44509
|
+
function formatCoderScriptFilePath(relativeFilePath) {
|
|
44510
|
+
return `./${formatDisplayPath(relativeFilePath)}`;
|
|
44131
44511
|
}
|
|
44132
44512
|
// Note: [🟡] Code for coder init package scripts [getDefaultCoderPackageJsonScripts](src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts) should never be published outside of `@promptbook/cli`
|
|
44513
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44133
44514
|
|
|
44134
44515
|
/**
|
|
44135
44516
|
* Loads the TypeScript runtime used for parsing JSONC-style project files.
|
|
@@ -44162,6 +44543,9 @@
|
|
|
44162
44543
|
/**
|
|
44163
44544
|
* Ensures one JSON object field contains the provided string-record entries.
|
|
44164
44545
|
*
|
|
44546
|
+
* Entries which the project already defines are **never** overridden - only missing keys are added,
|
|
44547
|
+
* so hand-tuned scripts and settings survive every repeated `ptbk coder init`.
|
|
44548
|
+
*
|
|
44165
44549
|
* @private function of `initializeCoderProjectConfiguration`
|
|
44166
44550
|
*/
|
|
44167
44551
|
async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldPath, nextEntries, ensureParentDirectoryPath, }) {
|
|
@@ -44173,21 +44557,24 @@
|
|
|
44173
44557
|
const formatting = detectJsonFileFormatting(fileContent);
|
|
44174
44558
|
const jsonObject = fileContent === undefined ? {} : await parseJsonObjectFile(relativeFilePath, fileContent);
|
|
44175
44559
|
const existingEntries = getStringRecordOrDefault(jsonObject[fieldPath], relativeFilePath, fieldPath);
|
|
44176
|
-
|
|
44560
|
+
const addedEntryKeys = [];
|
|
44177
44561
|
const mergedEntries = { ...existingEntries };
|
|
44178
44562
|
for (const [entryKey, entryValue] of Object.entries(nextEntries)) {
|
|
44179
|
-
if (mergedEntries
|
|
44180
|
-
|
|
44181
|
-
|
|
44563
|
+
if (Object.prototype.hasOwnProperty.call(mergedEntries, entryKey)) {
|
|
44564
|
+
// Note: The project already defines this entry, keep its own value untouched
|
|
44565
|
+
continue;
|
|
44182
44566
|
}
|
|
44567
|
+
mergedEntries[entryKey] = entryValue;
|
|
44568
|
+
addedEntryKeys.push(entryKey);
|
|
44183
44569
|
}
|
|
44570
|
+
const hasChanges = fileContent === undefined || addedEntryKeys.length > 0;
|
|
44184
44571
|
if (!hasChanges) {
|
|
44185
|
-
return 'unchanged';
|
|
44572
|
+
return { status: 'unchanged', addedEntryKeys };
|
|
44186
44573
|
}
|
|
44187
44574
|
const nextJsonObject = { ...jsonObject };
|
|
44188
44575
|
nextJsonObject[fieldPath] = mergedEntries;
|
|
44189
44576
|
await promises.writeFile(absoluteFilePath, serializeJsonObject(nextJsonObject, formatting), 'utf-8');
|
|
44190
|
-
return fileContent === undefined ? 'created' : 'updated';
|
|
44577
|
+
return { status: fileContent === undefined ? 'created' : 'updated', addedEntryKeys };
|
|
44191
44578
|
}
|
|
44192
44579
|
/**
|
|
44193
44580
|
* Parses one JSON object file while accepting VS Code style comments and trailing commas.
|
|
@@ -44276,6 +44663,8 @@
|
|
|
44276
44663
|
/**
|
|
44277
44664
|
* Ensures `package.json` contains the standalone Promptbook coder helper scripts.
|
|
44278
44665
|
*
|
|
44666
|
+
* Scripts which the project already defines are kept as they are, only missing ones are added.
|
|
44667
|
+
*
|
|
44279
44668
|
* @private function of `initializeCoderProjectConfiguration`
|
|
44280
44669
|
*/
|
|
44281
44670
|
async function ensureCoderPackageJsonFile(projectPath) {
|
|
@@ -44329,17 +44718,20 @@
|
|
|
44329
44718
|
/**
|
|
44330
44719
|
* Ensures VS Code routes pasted prompt images into `prompts/screenshots`.
|
|
44331
44720
|
*
|
|
44721
|
+
* Settings which the project already defines are kept as they are, only missing ones are added.
|
|
44722
|
+
*
|
|
44332
44723
|
* @private function of `initializeCoderProjectConfiguration`
|
|
44333
44724
|
*/
|
|
44334
44725
|
async function ensureCoderVscodeSettingsFile(projectPath) {
|
|
44335
44726
|
const [fieldPath, nextEntries] = resolveDefaultCoderVscodeSettingsEntry();
|
|
44336
|
-
|
|
44727
|
+
const { status } = await mergeStringRecordJsonFile({
|
|
44337
44728
|
projectPath,
|
|
44338
44729
|
relativeFilePath: VSCODE_SETTINGS_FILE_PATH,
|
|
44339
44730
|
fieldPath,
|
|
44340
44731
|
nextEntries,
|
|
44341
44732
|
ensureParentDirectoryPath: VSCODE_DIRECTORY_PATH,
|
|
44342
44733
|
});
|
|
44734
|
+
return status;
|
|
44343
44735
|
}
|
|
44344
44736
|
/**
|
|
44345
44737
|
* Resolves the default string-record entry that `coder init` merges into VS Code settings.
|
|
@@ -44356,34 +44748,32 @@
|
|
|
44356
44748
|
/**
|
|
44357
44749
|
* Creates or updates all coder configuration artifacts required in the current project.
|
|
44358
44750
|
*
|
|
44751
|
+
* Nothing the project already owns is ever overwritten - existing scripts, settings and files are kept as they are,
|
|
44752
|
+
* and the artifacts they would reference are created only together with the scripts which actually reference them.
|
|
44753
|
+
*
|
|
44359
44754
|
* @private internal utility of `coder init` command
|
|
44360
44755
|
*/
|
|
44361
44756
|
async function initializeCoderProjectConfiguration(projectPath) {
|
|
44362
44757
|
const promptsDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_DIRECTORY_PATH$1);
|
|
44363
44758
|
const promptsDoneDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_DONE_DIRECTORY_PATH);
|
|
44364
44759
|
const promptsTemplatesDirectoryStatus = await ensureDirectory(projectPath, PROMPTS_TEMPLATES_DIRECTORY_PATH);
|
|
44365
|
-
const promptTemplateFileStatuses = await ensureDefaultCoderPromptTemplateFiles(projectPath);
|
|
44366
44760
|
const agentsDirectoryStatus = await ensureDirectory(projectPath, CODER_AGENTS_DIRECTORY_PATH);
|
|
44367
|
-
const developerAgentFileStatus = await ensureCoderDeveloperAgentFile(projectPath);
|
|
44368
|
-
const agentsFileStatus = await ensureCoderMarkdownFile(projectPath, AGENTS_FILE_PATH, getDefaultCoderAgentsFileContent());
|
|
44369
|
-
const agentCodingFileStatus = await ensureCoderMarkdownFile(projectPath, AGENT_CODING_FILE_PATH, getDefaultCoderAgentCodingFileContent());
|
|
44370
44761
|
const { envFileStatus, initializedEnvVariableNames } = await ensureCoderEnvFile(projectPath);
|
|
44371
44762
|
const gitignoreFileStatus = await ensureCoderGitignoreFile(projectPath);
|
|
44372
|
-
const packageJsonFileStatus = await ensureCoderPackageJsonFile(projectPath);
|
|
44763
|
+
const { status: packageJsonFileStatus, addedEntryKeys: addedPackageJsonScriptNames } = await ensureCoderPackageJsonFile(projectPath);
|
|
44373
44764
|
const vscodeSettingsFileStatus = await ensureCoderVscodeSettingsFile(projectPath);
|
|
44765
|
+
const referencedArtifactStatuses = await ensureCoderReferencedArtifacts(projectPath, resolveCoderPackageJsonScriptReferencedArtifactPaths(addedPackageJsonScriptNames));
|
|
44374
44766
|
return {
|
|
44375
44767
|
promptsDirectoryStatus,
|
|
44376
44768
|
promptsDoneDirectoryStatus,
|
|
44377
44769
|
promptsTemplatesDirectoryStatus,
|
|
44378
|
-
promptTemplateFileStatuses,
|
|
44379
44770
|
agentsDirectoryStatus,
|
|
44380
|
-
developerAgentFileStatus,
|
|
44381
|
-
agentsFileStatus,
|
|
44382
|
-
agentCodingFileStatus,
|
|
44383
44771
|
envFileStatus,
|
|
44384
44772
|
gitignoreFileStatus,
|
|
44385
44773
|
packageJsonFileStatus,
|
|
44386
44774
|
vscodeSettingsFileStatus,
|
|
44775
|
+
addedPackageJsonScriptNames,
|
|
44776
|
+
referencedArtifactStatuses,
|
|
44387
44777
|
initializedEnvVariableNames,
|
|
44388
44778
|
};
|
|
44389
44779
|
}
|
|
@@ -44399,17 +44789,20 @@
|
|
|
44399
44789
|
printInitializationStatusLine('prompts/', summary.promptsDirectoryStatus);
|
|
44400
44790
|
printInitializationStatusLine('prompts/done/', summary.promptsDoneDirectoryStatus);
|
|
44401
44791
|
printInitializationStatusLine('prompts/templates/', summary.promptsTemplatesDirectoryStatus);
|
|
44402
|
-
for (const templateFileStatus of summary.promptTemplateFileStatuses) {
|
|
44403
|
-
printInitializationStatusLine(formatDisplayPath(templateFileStatus.relativeFilePath), templateFileStatus.status);
|
|
44404
|
-
}
|
|
44405
44792
|
printInitializationStatusLine('agents/', summary.agentsDirectoryStatus);
|
|
44406
|
-
printInitializationStatusLine(CODER_DEVELOPER_AGENT_FILE_PATH, summary.developerAgentFileStatus);
|
|
44407
|
-
printInitializationStatusLine(AGENTS_FILE_PATH, summary.agentsFileStatus);
|
|
44408
|
-
printInitializationStatusLine(AGENT_CODING_FILE_PATH, summary.agentCodingFileStatus);
|
|
44409
44793
|
printInitializationStatusLine('.env', summary.envFileStatus);
|
|
44410
44794
|
printInitializationStatusLine('.gitignore', summary.gitignoreFileStatus);
|
|
44411
44795
|
printInitializationStatusLine('package.json', summary.packageJsonFileStatus);
|
|
44412
44796
|
printInitializationStatusLine('.vscode/settings.json', summary.vscodeSettingsFileStatus);
|
|
44797
|
+
for (const referencedArtifactStatus of summary.referencedArtifactStatuses) {
|
|
44798
|
+
printInitializationStatusLine(formatDisplayPath(referencedArtifactStatus.relativeFilePath), referencedArtifactStatus.status);
|
|
44799
|
+
}
|
|
44800
|
+
if (summary.addedPackageJsonScriptNames.length > 0) {
|
|
44801
|
+
printInitializationNote(`Added npm scripts: ${summary.addedPackageJsonScriptNames.join(', ')}`, colors__default["default"].cyan);
|
|
44802
|
+
}
|
|
44803
|
+
else {
|
|
44804
|
+
printInitializationNote('All Promptbook coder npm scripts are already present.', colors__default["default"].gray);
|
|
44805
|
+
}
|
|
44413
44806
|
if (summary.initializedEnvVariableNames.length > 0) {
|
|
44414
44807
|
printInitializationNote(`Added env variables: ${summary.initializedEnvVariableNames.join(', ')}`, colors__default["default"].cyan);
|
|
44415
44808
|
}
|
|
@@ -44427,6 +44820,9 @@
|
|
|
44427
44820
|
if (status === 'updated') {
|
|
44428
44821
|
return 'updated';
|
|
44429
44822
|
}
|
|
44823
|
+
if (status === 'not-referenced') {
|
|
44824
|
+
return 'not referenced by the added scripts, kept as is';
|
|
44825
|
+
}
|
|
44430
44826
|
return 'unchanged';
|
|
44431
44827
|
}
|
|
44432
44828
|
/**
|
|
@@ -44469,39 +44865,48 @@
|
|
|
44469
44865
|
${block(listDefaultCoderProjectPromptTemplateDisplayPaths())}
|
|
44470
44866
|
- ${CODER_DEVELOPER_AGENT_FILE_PATH}
|
|
44471
44867
|
- ${AGENTS_FILE_PATH}
|
|
44472
|
-
- ${AGENT_CODING_FILE_PATH}
|
|
44473
44868
|
- .gitignore with local artifacts from every supported harness
|
|
44474
44869
|
- package.json
|
|
44475
44870
|
- .vscode/settings.json
|
|
44476
44871
|
|
|
44872
|
+
Never overwrites what the project already owns:
|
|
44873
|
+
- Existing package.json scripts and .vscode/settings.json settings are kept, only missing ones are added
|
|
44874
|
+
- Files referenced by a script, like the agent and context of coder:run, are created only together
|
|
44875
|
+
with the script which references them
|
|
44876
|
+
|
|
44477
44877
|
Ensures required coding-agent environment variables in .env:
|
|
44478
44878
|
- CODING_AGENT_GIT_NAME
|
|
44479
44879
|
- CODING_AGENT_GIT_EMAIL
|
|
44480
44880
|
- CODING_AGENT_GIT_SIGNING_KEY
|
|
44481
44881
|
|
|
44482
|
-
Checks that the coding harnesses are installed and up to date unless \`--no-
|
|
44882
|
+
Checks that the coding harnesses are installed and up to date unless \`--no-questions\` is used:
|
|
44483
44883
|
${block(listCheckedHarnessLabels())}
|
|
44484
44884
|
|
|
44485
44885
|
${block(CODER_GIT_SYNC_DESCRIPTION)}
|
|
44886
|
+
|
|
44887
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
44486
44888
|
`));
|
|
44487
44889
|
addCoderGitSyncOptions(command);
|
|
44488
|
-
|
|
44890
|
+
addQuestionsOption(command);
|
|
44489
44891
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44490
44892
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
44491
|
-
const
|
|
44893
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
44492
44894
|
const projectPath = process.cwd();
|
|
44493
44895
|
// Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
|
|
44494
44896
|
const { $commitCoderChanges, $startCoderGitSync } = await Promise.resolve().then(function () { return coderGitSync; });
|
|
44495
44897
|
const commitScope = await $startCoderGitSync({ gitSync, projectPath });
|
|
44898
|
+
const isPromptsDirectoryEmpty = await isDirectoryEmpty(projectPath, PROMPTS_DIRECTORY_PATH$1);
|
|
44496
44899
|
const summary = await initializeCoderProjectConfiguration(projectPath);
|
|
44497
44900
|
printInitializationSummary(summary);
|
|
44498
|
-
|
|
44901
|
+
if (isPromptsDirectoryEmpty) {
|
|
44902
|
+
await generatePromptBoilerplate({ projectPath, boilerplateCount: DEFAULT_BOILERPLATE_COUNT });
|
|
44903
|
+
}
|
|
44499
44904
|
await $commitCoderChanges({
|
|
44500
44905
|
gitSync,
|
|
44501
44906
|
commitScope,
|
|
44502
44907
|
commitMessage: 'Initialize Promptbook Coder',
|
|
44503
44908
|
});
|
|
44504
|
-
await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES,
|
|
44909
|
+
await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES, questionsOptions);
|
|
44505
44910
|
}));
|
|
44506
44911
|
}
|
|
44507
44912
|
/**
|
|
@@ -44558,6 +44963,23 @@
|
|
|
44558
44963
|
// Note: [🟡] Code for CLI prompt priority options [promptPriorityCliOptions](src/cli/cli-commands/common/promptPriorityCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
44559
44964
|
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44560
44965
|
|
|
44966
|
+
/**
|
|
44967
|
+
* Description shared by coder commands which accept an agent Book.
|
|
44968
|
+
*
|
|
44969
|
+
* @private internal utility of `ptbk coder`
|
|
44970
|
+
*/
|
|
44971
|
+
const CODER_AGENT_OPTION_DESCRIPTION = 'Path to a .book file used to personalize coding prompts and select agent-specific tasks';
|
|
44972
|
+
/**
|
|
44973
|
+
* Registers the shared `--agent` option for coder commands.
|
|
44974
|
+
*
|
|
44975
|
+
* @private internal utility of `ptbk coder`
|
|
44976
|
+
*/
|
|
44977
|
+
function addCoderAgentOption(command) {
|
|
44978
|
+
command.option('--agent <agent-book-path>', CODER_AGENT_OPTION_DESCRIPTION);
|
|
44979
|
+
}
|
|
44980
|
+
// Note: [🟡] Code for CLI coder agent options should never be published outside of `@promptbook/cli`
|
|
44981
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
44982
|
+
|
|
44561
44983
|
/**
|
|
44562
44984
|
* Initializes `coder list` command for Promptbook CLI utilities.
|
|
44563
44985
|
*
|
|
@@ -44575,19 +44997,27 @@
|
|
|
44575
44997
|
Features:
|
|
44576
44998
|
- Lists only ready, fully authored prompts
|
|
44577
44999
|
- Groups prompts from highest to lowest priority
|
|
44578
|
-
- Optional --harness and --
|
|
45000
|
+
- Optional --harness, --model and --agent filters show only prompts compatible with that selection
|
|
44579
45001
|
- Does not start a coding harness or modify prompt files
|
|
44580
45002
|
`));
|
|
44581
45003
|
addPromptRunnerSelectionOptions(command);
|
|
45004
|
+
addCoderAgentOption(command);
|
|
44582
45005
|
addPromptPriorityOptions(command);
|
|
44583
45006
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44584
|
-
const { priority, minPriority: minimumPriority, maxPriority: maximumPriority, } = cliOptions;
|
|
45007
|
+
const { agent, priority, minPriority: minimumPriority, maxPriority: maximumPriority, } = cliOptions;
|
|
44585
45008
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: false });
|
|
44586
|
-
const
|
|
45009
|
+
const resolvedCoderAgentBook = agent === undefined
|
|
45010
|
+
? undefined
|
|
45011
|
+
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; }))
|
|
45012
|
+
.resolveCoderAgentBook(agent, process.cwd());
|
|
45013
|
+
const promptRunnerIdentity = runnerOptions.agentName === undefined &&
|
|
45014
|
+
runnerOptions.model === undefined &&
|
|
45015
|
+
resolvedCoderAgentBook === undefined
|
|
44587
45016
|
? undefined
|
|
44588
45017
|
: {
|
|
44589
45018
|
harnessName: runnerOptions.agentName,
|
|
44590
45019
|
modelName: runnerOptions.model,
|
|
45020
|
+
agentReferences: resolvedCoderAgentBook === null || resolvedCoderAgentBook === void 0 ? void 0 : resolvedCoderAgentBook.agentReferences,
|
|
44591
45021
|
};
|
|
44592
45022
|
// Note: Import dynamically to avoid loading prompt parsing dependencies until this command is used.
|
|
44593
45023
|
const { listCoderPrompts } = await Promise.resolve().then(function () { return listCoderPrompts$1; });
|
|
@@ -44655,7 +45085,7 @@
|
|
|
44655
45085
|
*
|
|
44656
45086
|
* @private internal utility of `ptbk coder`
|
|
44657
45087
|
*/
|
|
44658
|
-
async function $ensureCoderHarnessGitignoreRules(projectPath, harnessName) {
|
|
45088
|
+
async function $ensureCoderHarnessGitignoreRules(projectPath, harnessName, questionsOptions) {
|
|
44659
45089
|
if (harnessName === undefined) {
|
|
44660
45090
|
return;
|
|
44661
45091
|
}
|
|
@@ -44666,7 +45096,7 @@
|
|
|
44666
45096
|
const { label } = getHarnessDefinition(harnessName);
|
|
44667
45097
|
const formattedRules = formatGitignoreRules(missingRules);
|
|
44668
45098
|
const entryLabel = missingRules.length === 1 ? 'entry' : 'entries';
|
|
44669
|
-
const isAdditionApproved = await $askForConfirmation(`Add the missing ${label} ignore ${entryLabel} ${formattedRules} to \`.gitignore\` now
|
|
45099
|
+
const isAdditionApproved = await $askForConfirmation(`Add the missing ${label} ignore ${entryLabel} ${formattedRules} to \`.gitignore\` now?`, questionsOptions);
|
|
44670
45100
|
if (!isAdditionApproved) {
|
|
44671
45101
|
console.info(colors__default["default"].gray(`Skipped, add ${formattedRules} to \`.gitignore\` manually.`));
|
|
44672
45102
|
return;
|
|
@@ -44691,22 +45121,24 @@
|
|
|
44691
45121
|
*/
|
|
44692
45122
|
function $initializeCoderPingCommand(program) {
|
|
44693
45123
|
const command = program.command('ping');
|
|
44694
|
-
command.description(_spaceTrim.spaceTrim(`
|
|
44695
|
-
|
|
45124
|
+
command.description(_spaceTrim.spaceTrim((block) => `
|
|
45125
|
+
Send one tiny dummy prompt to a harness and model to measure and warm them up
|
|
44696
45126
|
|
|
44697
|
-
|
|
45127
|
+
${block(PROMPT_RUNNER_DESCRIPTION)}
|
|
44698
45128
|
|
|
44699
|
-
|
|
44700
|
-
|
|
44701
|
-
|
|
44702
|
-
|
|
44703
|
-
|
|
44704
|
-
|
|
44705
|
-
|
|
44706
|
-
|
|
44707
|
-
|
|
45129
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
45130
|
+
|
|
45131
|
+
Features:
|
|
45132
|
+
- Verifies that the selected harness, model, thinking level and authentication really work
|
|
45133
|
+
- Reports the answer of the harness, the response time and the reported usage
|
|
45134
|
+
- Starts the hourly/weekly quota window before you need it, so it is already refreshing when you do
|
|
45135
|
+
- Optional --period keeps the quota window refreshing by pinging once per period until stopped
|
|
45136
|
+
- Makes no coding changes or commits; if the selected harness has missing local ignore rules, offers to add them to .gitignore
|
|
45137
|
+
- Checks that the selected harness is installed and up to date unless --no-questions is used
|
|
45138
|
+
- Use --no-ui to stream the raw harness output instead of only the compact result
|
|
45139
|
+
`));
|
|
44708
45140
|
addPromptRunnerSelectionOptions(command);
|
|
44709
|
-
|
|
45141
|
+
addQuestionsOption(command);
|
|
44710
45142
|
addPromptRunnerRuntimeOptions(command);
|
|
44711
45143
|
command.option('--period <duration>', _spaceTrim.spaceTrim(`
|
|
44712
45144
|
Keep pinging once per period instead of pinging only once.
|
|
@@ -44715,11 +45147,11 @@
|
|
|
44715
45147
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44716
45148
|
const { period: periodValue } = cliOptions;
|
|
44717
45149
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: true });
|
|
44718
|
-
const
|
|
45150
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
44719
45151
|
// Note: The period is validated before the harness installation check, so a mistyped duration fails fast
|
|
44720
45152
|
const periodMs = parseOptionalPeriodDuration('--period', periodValue);
|
|
44721
|
-
await $ensureHarnessInstallations([runnerOptions.agentName],
|
|
44722
|
-
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
45153
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
45154
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName, questionsOptions);
|
|
44723
45155
|
const pingOptions = {
|
|
44724
45156
|
agentName: runnerOptions.agentName,
|
|
44725
45157
|
model: runnerOptions.model,
|
|
@@ -44742,6 +45174,159 @@
|
|
|
44742
45174
|
// Note: [🟡] Code for CLI command [ping](src/cli/cli-commands/coder/ping.ts) should never be published outside of `@promptbook/cli`
|
|
44743
45175
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
44744
45176
|
|
|
45177
|
+
/**
|
|
45178
|
+
* Free disk space below which `ptbk coder` refuses to start a new run.
|
|
45179
|
+
*
|
|
45180
|
+
* A coding round writes prompt and log artifacts, lets the harness rewrite the project, may install npm packages,
|
|
45181
|
+
* may create a git worktree for `--isolate` and usually runs a build, so a run started with less than this
|
|
45182
|
+
* would very likely die somewhere in the middle with a filesystem error.
|
|
45183
|
+
*
|
|
45184
|
+
* @private internal utility of `promptbookCli`
|
|
45185
|
+
*/
|
|
45186
|
+
const LOW_FREE_DISK_SPACE_BYTES = 2 * 1024 * 1024 * 1024;
|
|
45187
|
+
/**
|
|
45188
|
+
* Free disk space below which a started `ptbk coder` run stops at its next checkpoint and waits until space is freed.
|
|
45189
|
+
*
|
|
45190
|
+
* This limit is lower than `LOW_FREE_DISK_SPACE_BYTES`, because interrupting a run which is already in progress
|
|
45191
|
+
* is more expensive than not starting one at all.
|
|
45192
|
+
*
|
|
45193
|
+
* @private internal utility of `promptbookCli`
|
|
45194
|
+
*/
|
|
45195
|
+
const CRITICALLY_LOW_FREE_DISK_SPACE_BYTES = 1 * 1024 * 1024 * 1024;
|
|
45196
|
+
/**
|
|
45197
|
+
* How long one free disk space measurement is reused before the filesystem is measured again during a run.
|
|
45198
|
+
*
|
|
45199
|
+
* Pause checkpoints are passed very often - for example on every tick of a timed wait - so without this
|
|
45200
|
+
* interval the filesystem would be measured many times per second.
|
|
45201
|
+
*
|
|
45202
|
+
* @private internal utility of `promptbookCli`
|
|
45203
|
+
*/
|
|
45204
|
+
const FREE_DISK_SPACE_RECHECK_INTERVAL_MS = 60 * 1000;
|
|
45205
|
+
// 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`
|
|
45206
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
45207
|
+
|
|
45208
|
+
/**
|
|
45209
|
+
* Classifies one measured amount of free disk space against the `ptbk coder` free disk space limits.
|
|
45210
|
+
*
|
|
45211
|
+
* @private internal utility of `promptbookCli`
|
|
45212
|
+
*/
|
|
45213
|
+
function resolveFreeDiskSpaceLevel(availableBytes) {
|
|
45214
|
+
if (availableBytes < CRITICALLY_LOW_FREE_DISK_SPACE_BYTES) {
|
|
45215
|
+
return 'critical';
|
|
45216
|
+
}
|
|
45217
|
+
if (availableBytes < LOW_FREE_DISK_SPACE_BYTES) {
|
|
45218
|
+
return 'low';
|
|
45219
|
+
}
|
|
45220
|
+
return 'sufficient';
|
|
45221
|
+
}
|
|
45222
|
+
// 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`
|
|
45223
|
+
|
|
45224
|
+
/**
|
|
45225
|
+
* Measures the free disk space on the filesystem which hosts the given path.
|
|
45226
|
+
*
|
|
45227
|
+
* Note: `$` is used to indicate that this function is not a pure function - it reads the state of the filesystem
|
|
45228
|
+
*
|
|
45229
|
+
* @returns the measurement, or `null` when the filesystem can not be measured, for example on a platform which
|
|
45230
|
+
* does not report filesystem statistics - a run is never stopped by a measurement which could not be taken
|
|
45231
|
+
* @private internal utility of `promptbookCli`
|
|
45232
|
+
*/
|
|
45233
|
+
async function $readFreeDiskSpaceStatus(inspectedPath) {
|
|
45234
|
+
try {
|
|
45235
|
+
const fileSystemStats = await promises.statfs(inspectedPath);
|
|
45236
|
+
const blockSizeBytes = fileSystemStats.bsize;
|
|
45237
|
+
const availableBytes = fileSystemStats.bavail * blockSizeBytes;
|
|
45238
|
+
const totalBytes = fileSystemStats.blocks * blockSizeBytes;
|
|
45239
|
+
if (!Number.isFinite(availableBytes) || availableBytes < 0) {
|
|
45240
|
+
return null;
|
|
45241
|
+
}
|
|
45242
|
+
return {
|
|
45243
|
+
inspectedPath,
|
|
45244
|
+
availableBytes,
|
|
45245
|
+
totalBytes,
|
|
45246
|
+
level: resolveFreeDiskSpaceLevel(availableBytes),
|
|
45247
|
+
};
|
|
45248
|
+
}
|
|
45249
|
+
catch (_a) {
|
|
45250
|
+
// Note: A path or a platform which can not report its free disk space must not stop `ptbk coder` from running
|
|
45251
|
+
return null;
|
|
45252
|
+
}
|
|
45253
|
+
}
|
|
45254
|
+
// 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`
|
|
45255
|
+
|
|
45256
|
+
/**
|
|
45257
|
+
* Byte units used when one amount of disk space is written for a human.
|
|
45258
|
+
*/
|
|
45259
|
+
const FREE_DISK_SPACE_BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
|
45260
|
+
/**
|
|
45261
|
+
* Writes one byte count as a compact human-readable amount of disk space, for example `812 MB` or `1.5 GB`.
|
|
45262
|
+
*
|
|
45263
|
+
* @private internal utility of `promptbookCli`
|
|
45264
|
+
*/
|
|
45265
|
+
function formatFreeDiskSpaceBytes(bytes) {
|
|
45266
|
+
if (!Number.isFinite(bytes) || bytes <= 0) {
|
|
45267
|
+
return '0 B';
|
|
45268
|
+
}
|
|
45269
|
+
const unitIndex = Math.min(FREE_DISK_SPACE_BYTE_UNITS.length - 1, Math.floor(Math.log(bytes) / Math.log(1024)));
|
|
45270
|
+
const value = bytes / Math.pow(1024, unitIndex);
|
|
45271
|
+
// Note: One decimal place only matters for small values, `476 GB` is more readable than `476.3 GB`
|
|
45272
|
+
const decimalPlaceCount = value >= 10 || unitIndex === 0 ? 0 : 1;
|
|
45273
|
+
// Note: An empty decimal place only adds noise, `2 GB` is more readable than `2.0 GB`
|
|
45274
|
+
const displayedValue = value.toFixed(decimalPlaceCount).replace(/\.0$/, '');
|
|
45275
|
+
return `${displayedValue} ${FREE_DISK_SPACE_BYTE_UNITS[unitIndex]}`;
|
|
45276
|
+
}
|
|
45277
|
+
// 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`
|
|
45278
|
+
|
|
45279
|
+
/**
|
|
45280
|
+
* Writes the shared warning which explains one low free disk space measurement and how to get out of it.
|
|
45281
|
+
*
|
|
45282
|
+
* The very same wording is used by the check which refuses to start a run and by the check which pauses
|
|
45283
|
+
* a run that ran out of disk space while it was working.
|
|
45284
|
+
*
|
|
45285
|
+
* @private internal utility of `promptbookCli`
|
|
45286
|
+
*/
|
|
45287
|
+
function formatLowFreeDiskSpaceWarning(freeDiskSpaceStatus) {
|
|
45288
|
+
const { inspectedPath } = freeDiskSpaceStatus;
|
|
45289
|
+
const availableSpace = formatFreeDiskSpaceBytes(freeDiskSpaceStatus.availableBytes);
|
|
45290
|
+
const totalSpace = formatFreeDiskSpaceBytes(freeDiskSpaceStatus.totalBytes);
|
|
45291
|
+
const requiredSpaceToStart = formatFreeDiskSpaceBytes(LOW_FREE_DISK_SPACE_BYTES);
|
|
45292
|
+
const requiredSpaceToContinue = formatFreeDiskSpaceBytes(CRITICALLY_LOW_FREE_DISK_SPACE_BYTES);
|
|
45293
|
+
return _spaceTrim.spaceTrim(`
|
|
45294
|
+
Only **${availableSpace}** of ${totalSpace} is left on the disk which hosts \`${inspectedPath}\`.
|
|
45295
|
+
|
|
45296
|
+
**\`ptbk coder\` needs at least ${requiredSpaceToStart} of free disk space to start a run and at least ${requiredSpaceToContinue} to keep one running.**
|
|
45297
|
+
|
|
45298
|
+
Actionable hints:
|
|
45299
|
+
- Free up disk space on the drive which hosts \`${inspectedPath}\`.
|
|
45300
|
+
- Remove build artifacts, package caches and \`node_modules\` folders of projects you are not working on.
|
|
45301
|
+
- Remove the temporary worktrees which earlier \`--isolate\` runs left behind.
|
|
45302
|
+
`);
|
|
45303
|
+
}
|
|
45304
|
+
// 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`
|
|
45305
|
+
|
|
45306
|
+
/**
|
|
45307
|
+
* Refuses to start one `ptbk coder` command when the disk which hosts the project is nearly full.
|
|
45308
|
+
*
|
|
45309
|
+
* A run which starts without enough free disk space fails somewhere in the middle, after the coding agent has
|
|
45310
|
+
* already rewritten a part of the project, so it is stopped before it writes anything at all.
|
|
45311
|
+
*
|
|
45312
|
+
* Note: `$` is used to indicate that this function is not a pure function - it reads the state of the filesystem
|
|
45313
|
+
*
|
|
45314
|
+
* @throws {LimitReachedError} when there is not enough free disk space left to start
|
|
45315
|
+
* @private internal utility of `promptbookCli`
|
|
45316
|
+
*/
|
|
45317
|
+
async function $assertSufficientFreeDiskSpace(inspectedPath) {
|
|
45318
|
+
const freeDiskSpaceStatus = await $readFreeDiskSpaceStatus(inspectedPath);
|
|
45319
|
+
if (freeDiskSpaceStatus === null || freeDiskSpaceStatus.level === 'sufficient') {
|
|
45320
|
+
return;
|
|
45321
|
+
}
|
|
45322
|
+
throw new LimitReachedError(_spaceTrim.spaceTrim((block) => `
|
|
45323
|
+
There is not enough free disk space to run \`ptbk coder\`.
|
|
45324
|
+
|
|
45325
|
+
${block(formatLowFreeDiskSpaceWarning(freeDiskSpaceStatus))}
|
|
45326
|
+
`));
|
|
45327
|
+
}
|
|
45328
|
+
// 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`
|
|
45329
|
+
|
|
44745
45330
|
/**
|
|
44746
45331
|
* Npm packages which directly provide the `ptbk` executable.
|
|
44747
45332
|
*
|
|
@@ -45070,7 +45655,11 @@
|
|
|
45070
45655
|
* @returns `true` when at least one installation was updated and the current coder run should stop
|
|
45071
45656
|
* @private internal utility of `promptbookCli`
|
|
45072
45657
|
*/
|
|
45073
|
-
async function $ensurePromptbookCliInstallations() {
|
|
45658
|
+
async function $ensurePromptbookCliInstallations(questionsOptions) {
|
|
45659
|
+
if (!questionsOptions.isAskingQuestionsEnabled) {
|
|
45660
|
+
// Note: `--no-questions` forbids asking for the approval, so the registry checks would be useless
|
|
45661
|
+
return false;
|
|
45662
|
+
}
|
|
45074
45663
|
if (!process.stdin.isTTY) {
|
|
45075
45664
|
// Note: Non-interactive runs cannot approve an update and should not wait for registry checks
|
|
45076
45665
|
return false;
|
|
@@ -45082,7 +45671,7 @@
|
|
|
45082
45671
|
return false;
|
|
45083
45672
|
}
|
|
45084
45673
|
console.warn(colors__default["default"].yellow(formatPromptbookCliInstallationWarning(outdatedStatuses)));
|
|
45085
|
-
const isUpdateApproved = await $askForNpmPackageInstallationApproval('Update Promptbook CLI now?');
|
|
45674
|
+
const isUpdateApproved = await $askForNpmPackageInstallationApproval('Update Promptbook CLI now?', questionsOptions);
|
|
45086
45675
|
if (!isUpdateApproved) {
|
|
45087
45676
|
reportManualPromptbookCliUpdateCommands(outdatedStatuses);
|
|
45088
45677
|
return false;
|
|
@@ -45149,6 +45738,17 @@
|
|
|
45149
45738
|
return TEST_BEFORE_MODE_VALUES.includes(value);
|
|
45150
45739
|
}
|
|
45151
45740
|
|
|
45741
|
+
/**
|
|
45742
|
+
* Prints why a coder run has ended to the terminal.
|
|
45743
|
+
*
|
|
45744
|
+
* @private internal utility of `coder run` and `coder server` commands
|
|
45745
|
+
*/
|
|
45746
|
+
function printCoderRunFailure(error) {
|
|
45747
|
+
console.error(colors__default["default"].bgRed(`${error.name}`));
|
|
45748
|
+
console.error(colors__default["default"].red(formatUnknownErrorDetails(error)));
|
|
45749
|
+
}
|
|
45750
|
+
// Note: [🟡] Code for coder failure reporting [printCoderRunFailure](src/cli/cli-commands/coder/printCoderRunFailure.ts) should never be published outside of `@promptbook/cli`
|
|
45751
|
+
|
|
45152
45752
|
/**
|
|
45153
45753
|
* Initializes `coder run` command for Promptbook CLI utilities
|
|
45154
45754
|
*
|
|
@@ -45158,10 +45758,12 @@
|
|
|
45158
45758
|
*/
|
|
45159
45759
|
function $initializeCoderRunCommand(program) {
|
|
45160
45760
|
const command = program.command('run');
|
|
45161
|
-
command.description(_spaceTrim.spaceTrim(`
|
|
45761
|
+
command.description(_spaceTrim.spaceTrim((block) => `
|
|
45162
45762
|
Execute coding prompts through selected AI agent
|
|
45163
45763
|
|
|
45164
|
-
${PROMPT_RUNNER_DESCRIPTION}
|
|
45764
|
+
${block(PROMPT_RUNNER_DESCRIPTION)}
|
|
45765
|
+
|
|
45766
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
45165
45767
|
|
|
45166
45768
|
Features:
|
|
45167
45769
|
- Automatically stages and commits changes with agent identity unless --no-commit is used
|
|
@@ -45171,9 +45773,11 @@
|
|
|
45171
45773
|
- Optional post-commit git push with explicit --auto-push opt-in
|
|
45172
45774
|
- Optional pre-prompt git pull with explicit --auto-pull opt-in
|
|
45173
45775
|
- Optional --isolate runs every prompt in its own temporary git worktree and merges it back when verified
|
|
45776
|
+
- Saves the run trace of every round into prompts/traces/, named after its prompt file
|
|
45174
45777
|
- Optional --preserve-logs keeps temp prompt/log artifacts after successful rounds
|
|
45175
45778
|
- Optional --no-ui keeps plain streaming console output for logging and debugging
|
|
45176
|
-
-
|
|
45779
|
+
- Refuses to start on a nearly full disk and pauses the run when the free disk space becomes critical, unless --no-questions is used
|
|
45780
|
+
- Checks that the selected harness is installed and up to date before the first prompt unless --no-questions is used
|
|
45177
45781
|
- Offers to add missing project-local ignore rules for the selected harness
|
|
45178
45782
|
- In interactive mode, checks local and global Promptbook CLI installations and offers to update them
|
|
45179
45783
|
- Supports GPG signing of commits
|
|
@@ -45184,8 +45788,8 @@
|
|
|
45184
45788
|
`));
|
|
45185
45789
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
45186
45790
|
addPromptRunnerSelectionOptions(command);
|
|
45187
|
-
|
|
45188
|
-
command
|
|
45791
|
+
addQuestionsOption(command);
|
|
45792
|
+
addCoderAgentOption(command);
|
|
45189
45793
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
45190
45794
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
45191
45795
|
command.addOption(new commander.Option('--test-before <mode>', `Run tests before coding: ${TEST_BEFORE_MODE_VALUES.join(', ')} (defaults to no; uses npm test when --test is omitted)`)
|
|
@@ -45224,7 +45828,7 @@
|
|
|
45224
45828
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
45225
45829
|
isAgentRequired: !dryRun,
|
|
45226
45830
|
});
|
|
45227
|
-
const
|
|
45831
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
45228
45832
|
// [1] Parse the wait options and --no-auto:
|
|
45229
45833
|
// default: run automatically through the queue (no waiting between prompts)
|
|
45230
45834
|
// --no-auto: wait for user confirmation before each prompt (interactive mode)
|
|
@@ -45232,11 +45836,15 @@
|
|
|
45232
45836
|
// --wait-between-prompts: pace from start of one prompt to start of next
|
|
45233
45837
|
// --wait-after-error: wait before retrying after an error (default 10m)
|
|
45234
45838
|
const waitForUser = !auto;
|
|
45235
|
-
|
|
45839
|
+
assertUserConfirmationIsAllowed({ ...questionsOptions, isWaitingForUser: waitForUser });
|
|
45840
|
+
// Note: Checked before anything is installed or written, because installing a harness, updating the
|
|
45841
|
+
// Promptbook CLI and coding itself all need the disk space which is missing
|
|
45842
|
+
await $assertSufficientFreeDiskSpace(process.cwd());
|
|
45843
|
+
if (await $ensurePromptbookCliInstallations(questionsOptions)) {
|
|
45236
45844
|
return process.exit(0);
|
|
45237
45845
|
}
|
|
45238
|
-
await $ensureHarnessInstallations([runnerOptions.agentName],
|
|
45239
|
-
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
45846
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
45847
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName, questionsOptions);
|
|
45240
45848
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
45241
45849
|
const waitBetweenPrompts = parseOptionalWaitDuration(waitBetweenPromptsValue, 0);
|
|
45242
45850
|
const waitAfterError = parseOptionalWaitDuration(waitAfterErrorValue, DEFAULT_WAIT_AFTER_ERROR_MS$1);
|
|
@@ -45269,6 +45877,7 @@
|
|
|
45269
45877
|
allowDestructiveAutoMigrate,
|
|
45270
45878
|
autoPush: runnerOptions.autoPush,
|
|
45271
45879
|
autoPull: runnerOptions.autoPull,
|
|
45880
|
+
isAskingQuestionsEnabled: questionsOptions.isAskingQuestionsEnabled,
|
|
45272
45881
|
};
|
|
45273
45882
|
// Note: Import the function dynamically to avoid loading heavy dependencies until needed
|
|
45274
45883
|
const { runCodexPrompts } = await Promise.resolve().then(function () { return runCodexPrompts$1; });
|
|
@@ -45278,8 +45887,7 @@
|
|
|
45278
45887
|
}
|
|
45279
45888
|
catch (error) {
|
|
45280
45889
|
assertsError(error);
|
|
45281
|
-
|
|
45282
|
-
console.error(colors__default["default"].red(error.stack || error.message));
|
|
45890
|
+
printCoderRunFailure(error);
|
|
45283
45891
|
return process.exit(1);
|
|
45284
45892
|
}
|
|
45285
45893
|
return process.exit(0);
|
|
@@ -45323,28 +45931,31 @@
|
|
|
45323
45931
|
*/
|
|
45324
45932
|
function $initializeCoderServerCommand(program) {
|
|
45325
45933
|
const command = program.command('server');
|
|
45326
|
-
command.description(_spaceTrim.spaceTrim(`
|
|
45327
|
-
|
|
45934
|
+
command.description(_spaceTrim.spaceTrim((block) => `
|
|
45935
|
+
Start a coder server that watches for prompts and serves a kanban web UI
|
|
45328
45936
|
|
|
45329
|
-
|
|
45937
|
+
${block(PROMPT_RUNNER_DESCRIPTION)}
|
|
45330
45938
|
|
|
45331
|
-
|
|
45332
|
-
|
|
45333
|
-
|
|
45334
|
-
|
|
45335
|
-
|
|
45336
|
-
|
|
45337
|
-
|
|
45338
|
-
|
|
45339
|
-
|
|
45340
|
-
|
|
45939
|
+
${block(QUESTIONS_DESCRIPTION)}
|
|
45940
|
+
|
|
45941
|
+
Features:
|
|
45942
|
+
- Runs the same prompt processing as \`ptbk coder run\`
|
|
45943
|
+
- Refuses to start on a nearly full disk and pauses the run when the free disk space becomes critical, unless --no-questions is used
|
|
45944
|
+
- Checks that the selected harness is installed and up to date on startup unless --no-questions is used
|
|
45945
|
+
- Offers to add missing project-local ignore rules for the selected harness
|
|
45946
|
+
- Does not exit when all prompts are done; polls for new prompt files instead
|
|
45947
|
+
- Serves a kanban board at http://localhost:<port> for visual progress tracking
|
|
45948
|
+
- Allows editing prompt files directly from the browser (Trello-style)
|
|
45949
|
+
- Play / pause button in the browser stays in sync with the CLI pause state
|
|
45950
|
+
- Terminal controls match \`ptbk coder run\`: P pause/resume, S skip waiting, X end after current prompt
|
|
45951
|
+
`));
|
|
45341
45952
|
command.addOption(new commander.Option('--port <port>', 'Port to start the coder server on')
|
|
45342
45953
|
.env('PTBK_CODER_SERVER_PORT')
|
|
45343
45954
|
.default(DEFAULT_CODER_SERVER_PORT));
|
|
45344
45955
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
45345
45956
|
addPromptRunnerSelectionOptions(command);
|
|
45346
|
-
|
|
45347
|
-
command
|
|
45957
|
+
addQuestionsOption(command);
|
|
45958
|
+
addCoderAgentOption(command);
|
|
45348
45959
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
45349
45960
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
45350
45961
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
@@ -45373,11 +45984,15 @@
|
|
|
45373
45984
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
45374
45985
|
isAgentRequired: !dryRun,
|
|
45375
45986
|
});
|
|
45376
|
-
const
|
|
45377
|
-
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
45378
|
-
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName);
|
|
45987
|
+
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
45379
45988
|
// [1] Parse the wait options and --no-auto (same logic as `coder run`)
|
|
45380
45989
|
const waitForUser = !auto;
|
|
45990
|
+
assertUserConfirmationIsAllowed({ ...questionsOptions, isWaitingForUser: waitForUser });
|
|
45991
|
+
// Note: Checked before anything is installed or written, because installing a harness and coding
|
|
45992
|
+
// itself both need the disk space which is missing
|
|
45993
|
+
await $assertSufficientFreeDiskSpace(process.cwd());
|
|
45994
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
45995
|
+
await $ensureCoderHarnessGitignoreRules(process.cwd(), runnerOptions.agentName, questionsOptions);
|
|
45381
45996
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
45382
45997
|
const waitBetweenPrompts = parseOptionalWaitDuration(waitBetweenPromptsValue, 0);
|
|
45383
45998
|
const waitAfterError = parseOptionalWaitDuration(waitAfterErrorValue, DEFAULT_WAIT_AFTER_ERROR_MS$1);
|
|
@@ -45407,6 +46022,7 @@
|
|
|
45407
46022
|
allowDestructiveAutoMigrate,
|
|
45408
46023
|
autoPush: runnerOptions.autoPush,
|
|
45409
46024
|
autoPull: runnerOptions.autoPull,
|
|
46025
|
+
isAskingQuestionsEnabled: questionsOptions.isAskingQuestionsEnabled,
|
|
45410
46026
|
};
|
|
45411
46027
|
// Note: Import dynamically to avoid loading heavy dependencies until needed
|
|
45412
46028
|
const { runCodexPromptsServer } = await Promise.resolve().then(function () { return runCodexPromptsServer$1; });
|
|
@@ -45415,8 +46031,7 @@
|
|
|
45415
46031
|
}
|
|
45416
46032
|
catch (error) {
|
|
45417
46033
|
assertsError(error);
|
|
45418
|
-
|
|
45419
|
-
console.error(colors__default["default"].red(error.stack || error.message));
|
|
46034
|
+
printCoderRunFailure(error);
|
|
45420
46035
|
return process.exit(1);
|
|
45421
46036
|
}
|
|
45422
46037
|
return process.exit(0);
|
|
@@ -45605,11 +46220,7 @@
|
|
|
45605
46220
|
$initializeCoderVerifyCommand(coderCommand);
|
|
45606
46221
|
$initializeCoderFindFreshEmojiTagCommand(coderCommand);
|
|
45607
46222
|
// If no subcommand is provided, show help
|
|
45608
|
-
coderCommand
|
|
45609
|
-
console.info(colors__default["default"].yellow('Please specify a subcommand.'));
|
|
45610
|
-
console.info('');
|
|
45611
|
-
coderCommand.help();
|
|
45612
|
-
});
|
|
46223
|
+
$requireCliSubcommand(coderCommand);
|
|
45613
46224
|
}
|
|
45614
46225
|
// Note: [🟡] Code for CLI command [coder](src/cli/cli-commands/coder.ts) should never be published outside of `@promptbook/cli`
|
|
45615
46226
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -56199,7 +56810,9 @@
|
|
|
56199
56810
|
* @private internal function of `promptbookCli`
|
|
56200
56811
|
*/
|
|
56201
56812
|
function $initializeRunCommand(program) {
|
|
56202
|
-
|
|
56813
|
+
// Note: `run` is deprecated, so it is intentionally NOT the default command of `ptbk`
|
|
56814
|
+
// and it must be asked for explicitly
|
|
56815
|
+
const runCommand = program.command('run');
|
|
56203
56816
|
configureRunCommand(runCommand);
|
|
56204
56817
|
runCommand.action(handleActionErrors((pipelineSource, cliOptions) => runCommandAction(pipelineSource, cliOptions)));
|
|
56205
56818
|
}
|
|
@@ -58038,9 +58651,24 @@
|
|
|
58038
58651
|
command.option('--remote-server-url <url>', `URL of remote server to use when `, DEFAULT_REMOTE_SERVER_URL);
|
|
58039
58652
|
}
|
|
58040
58653
|
|
|
58654
|
+
/**
|
|
58655
|
+
* Keeps one already registered CLI command out of the help of its parent command while the command itself stays
|
|
58656
|
+
* fully usable - it can still be run, it still has its own help and it is still reachable through `ptbk help <command>`.
|
|
58657
|
+
*
|
|
58658
|
+
* Note: `$` is used to indicate that this function is not a pure function - it changes how the CLI renders its help
|
|
58659
|
+
*
|
|
58660
|
+
* @private utility of CLI
|
|
58661
|
+
*/
|
|
58662
|
+
function $hideCliCommandFromHelp(command) {
|
|
58663
|
+
command._hidden = true;
|
|
58664
|
+
}
|
|
58665
|
+
|
|
58041
58666
|
/**
|
|
58042
58667
|
* Marks one CLI command as deprecated while keeping it available for existing callers.
|
|
58043
58668
|
*
|
|
58669
|
+
* Deprecated commands are not advertised anymore - they are hidden from the list of commands in the help of their
|
|
58670
|
+
* parent command, they warn when they are used and they explain the deprecation in their own help.
|
|
58671
|
+
*
|
|
58044
58672
|
* @private utility of CLI
|
|
58045
58673
|
*/
|
|
58046
58674
|
function $deprecateCliCommand(command, deprecationMessage) {
|
|
@@ -58052,6 +58680,7 @@
|
|
|
58052
58680
|
command.hook('preAction', () => {
|
|
58053
58681
|
console.warn(colors__default["default"].yellow(createDeprecatedCliCommandWarning(command, deprecationMessage)));
|
|
58054
58682
|
});
|
|
58683
|
+
$hideCliCommandFromHelp(command);
|
|
58055
58684
|
}
|
|
58056
58685
|
/**
|
|
58057
58686
|
* Creates the runtime warning printed before a deprecated CLI command action starts.
|
|
@@ -58119,10 +58748,17 @@
|
|
|
58119
58748
|
program.version(PROMPTBOOK_ENGINE_VERSION);
|
|
58120
58749
|
program.description(CLAIM);
|
|
58121
58750
|
// Note: These options are valid for all commands
|
|
58751
|
+
// Note: Commands are listed in the help in the order they are registered,
|
|
58752
|
+
// `coder` is the most used one so it goes first and the deprecated ones,
|
|
58753
|
+
// which `$deprecateTopLevelCommands` hides from the help entirely, go last
|
|
58754
|
+
$initializeCoderCommand(program);
|
|
58755
|
+
$initializeAgentCommand(program);
|
|
58756
|
+
$initializeAgentFolderCommand(program);
|
|
58757
|
+
$initializeAgentsServerCommand(program);
|
|
58122
58758
|
$initializeAboutCommand(program);
|
|
58759
|
+
$initializeHelloCommand(program);
|
|
58123
58760
|
$initializeRunCommand(program);
|
|
58124
58761
|
$initializeLoginCommand(program);
|
|
58125
|
-
$initializeHelloCommand(program);
|
|
58126
58762
|
$initializeMakeCommand(program);
|
|
58127
58763
|
$initializePrettifyCommand(program);
|
|
58128
58764
|
$initializeTestCommand(program);
|
|
@@ -58130,16 +58766,13 @@
|
|
|
58130
58766
|
$initializeListScrapersCommand(program);
|
|
58131
58767
|
$initializeStartAgentsServerCommand(program);
|
|
58132
58768
|
$initializeStartPipelinesServerCommand(program);
|
|
58133
|
-
$initializeAgentCommand(program);
|
|
58134
|
-
$initializeAgentFolderCommand(program);
|
|
58135
|
-
$initializeAgentsServerCommand(program);
|
|
58136
|
-
$initializeCoderCommand(program);
|
|
58137
58769
|
$deprecateTopLevelCommands(program);
|
|
58138
58770
|
// TODO: [🧠] Should it be here or not> $addGlobalOptionsToCommand(program);
|
|
58139
58771
|
program.commands.forEach($addGlobalOptionsToCommand);
|
|
58772
|
+
// Note: There is no default command, so `ptbk` without a subcommand asks for one
|
|
58773
|
+
// instead of running the deprecated `ptbk run`
|
|
58140
58774
|
if (commandLineArguments.length === 0) {
|
|
58141
|
-
program
|
|
58142
|
-
return process.exit(0);
|
|
58775
|
+
return $reportMissingCliSubcommand(program);
|
|
58143
58776
|
}
|
|
58144
58777
|
program.parse(process.argv);
|
|
58145
58778
|
}
|
|
@@ -58153,7 +58786,7 @@
|
|
|
58153
58786
|
return firstCommandLineArgument !== undefined && VERSION_OPTION_ARGUMENTS.has(firstCommandLineArgument);
|
|
58154
58787
|
}
|
|
58155
58788
|
/**
|
|
58156
|
-
*
|
|
58789
|
+
* Marks each configured top-level legacy command as deprecated, which keeps it usable but takes it out of the help.
|
|
58157
58790
|
*/
|
|
58158
58791
|
function $deprecateTopLevelCommands(program) {
|
|
58159
58792
|
for (const command of program.commands) {
|
|
@@ -58164,7 +58797,6 @@
|
|
|
58164
58797
|
}
|
|
58165
58798
|
}
|
|
58166
58799
|
// Note: [🟡] Code for CLI program [promptbookCli](src/cli/promptbookCli.ts) should never be published outside of `@promptbook/cli`
|
|
58167
|
-
// TODO: [🧠] Maybe `run` command the default, instead of `ptbk run ./foo.book` -> `ptbk ./foo.book`
|
|
58168
58800
|
// TODO: [🥠] Do not export, its just for CLI script
|
|
58169
58801
|
// TODO: [🕌] When more functionalities, rename
|
|
58170
58802
|
// Note: 11:11
|
|
@@ -59276,7 +59908,9 @@
|
|
|
59276
59908
|
*/
|
|
59277
59909
|
function createExecutionToolsFromVercelProvider(options) {
|
|
59278
59910
|
let { title, description } = options;
|
|
59279
|
-
const { vercelProvider, availableModels,
|
|
59911
|
+
const { vercelProvider, availableModels, additionalChatSettings = {} } = options;
|
|
59912
|
+
// <- Note: `userId` is not forwarded, because Vercel AI SDK moved provider-specific settings like `user` from
|
|
59913
|
+
// `vercelProvider.chat(modelName, settings)` into `providerOptions` which are keyed by the provider
|
|
59280
59914
|
if (!/Vercel/i.test(title)) {
|
|
59281
59915
|
title = `${title} (through Vercel)`;
|
|
59282
59916
|
// <- TODO: [🧈] Maybe standartize the suffix
|
|
@@ -59317,10 +59951,7 @@
|
|
|
59317
59951
|
|
|
59318
59952
|
`));
|
|
59319
59953
|
}
|
|
59320
|
-
const model = await vercelProvider.chat(modelName
|
|
59321
|
-
user: (userId === null || userId === void 0 ? void 0 : userId.toString()) || undefined,
|
|
59322
|
-
...additionalChatSettings,
|
|
59323
|
-
});
|
|
59954
|
+
const model = await vercelProvider.chat(modelName);
|
|
59324
59955
|
const rawPromptContent = templateParameters(content, { ...parameters, modelName });
|
|
59325
59956
|
// Support for passing a chat thread (multi-message conversation)
|
|
59326
59957
|
let promptMessages;
|
|
@@ -59358,14 +59989,9 @@
|
|
|
59358
59989
|
}
|
|
59359
59990
|
const rawRequest = {
|
|
59360
59991
|
// <- TODO: [☂]
|
|
59361
|
-
inputFormat: 'messages',
|
|
59362
|
-
mode: {
|
|
59363
|
-
type: 'regular',
|
|
59364
|
-
tools: [
|
|
59365
|
-
/* <- TODO: Pass the tools */
|
|
59366
|
-
],
|
|
59367
|
-
},
|
|
59368
59992
|
prompt: promptMessages,
|
|
59993
|
+
// <- TODO: Pass the tools via `tools`
|
|
59994
|
+
...additionalChatSettings,
|
|
59369
59995
|
};
|
|
59370
59996
|
const start = $getCurrentDate();
|
|
59371
59997
|
if (options.isVerbose) {
|
|
@@ -59382,28 +60008,31 @@
|
|
|
59382
60008
|
if (options.isVerbose) {
|
|
59383
60009
|
console.info(colors__default["default"].bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
|
|
59384
60010
|
}
|
|
59385
|
-
|
|
60011
|
+
// Note: Vercel AI SDK returns ordered content parts, the chat message is made only of the text parts
|
|
60012
|
+
const responseTextParts = rawResponse.content.flatMap((contentPart) => contentPart.type === 'text' ? [contentPart.text] : []);
|
|
60013
|
+
if (responseTextParts.length === 0) {
|
|
59386
60014
|
throw new PipelineExecutionError('No response message');
|
|
59387
60015
|
}
|
|
60016
|
+
const responseText = responseTextParts.join('');
|
|
59388
60017
|
const complete = $getCurrentDate();
|
|
59389
60018
|
const duration = uncertainNumber((new Date(complete).getTime() - new Date(start).getTime()) / 1000);
|
|
59390
60019
|
const usage = {
|
|
59391
60020
|
price: UNCERTAIN_ZERO_VALUE,
|
|
59392
60021
|
duration,
|
|
59393
60022
|
input: {
|
|
59394
|
-
tokensCount: uncertainNumber(rawResponse.usage.
|
|
60023
|
+
tokensCount: uncertainNumber(rawResponse.usage.inputTokens),
|
|
59395
60024
|
...computeUsageCounts(rawPromptContent),
|
|
59396
60025
|
},
|
|
59397
60026
|
output: {
|
|
59398
|
-
tokensCount: uncertainNumber(rawResponse.usage.
|
|
59399
|
-
...computeUsageCounts(
|
|
60027
|
+
tokensCount: uncertainNumber(rawResponse.usage.outputTokens),
|
|
60028
|
+
...computeUsageCounts(responseText),
|
|
59400
60029
|
},
|
|
59401
60030
|
};
|
|
59402
60031
|
return exportJson({
|
|
59403
60032
|
name: 'promptResult',
|
|
59404
60033
|
message: `Result of \`createExecutionToolsFromVercelProvider.callChatModel\``,
|
|
59405
60034
|
value: {
|
|
59406
|
-
content:
|
|
60035
|
+
content: responseText,
|
|
59407
60036
|
modelName,
|
|
59408
60037
|
timing: {
|
|
59409
60038
|
start,
|
|
@@ -74708,13 +75337,15 @@
|
|
|
74708
75337
|
}
|
|
74709
75338
|
|
|
74710
75339
|
/**
|
|
74711
|
-
* Checks whether a prompt is unrestricted or matches the selected harness
|
|
75340
|
+
* Checks whether a prompt is unrestricted or matches the selected harness, model or Book agent.
|
|
74712
75341
|
*
|
|
74713
|
-
* A prompt status line can contain one or more backtick-delimited model or
|
|
74714
|
-
*
|
|
74715
|
-
* `gpt` selects any `gpt-*` model
|
|
75342
|
+
* A prompt status line can contain one or more backtick-delimited model, harness or agent
|
|
75343
|
+
* references. Matching is intentionally based on normalized substrings so a token such as
|
|
75344
|
+
* `gpt` selects any `gpt-*` model, `developer` selects an agent Book named `developer.book`,
|
|
75345
|
+
* and `opus` selects a `claude-opus-*` model.
|
|
74716
75346
|
*/
|
|
74717
75347
|
function isPromptCompatibleWithRunner(file, section, promptRunnerIdentity) {
|
|
75348
|
+
var _a;
|
|
74718
75349
|
if (promptRunnerIdentity === undefined) {
|
|
74719
75350
|
return true;
|
|
74720
75351
|
}
|
|
@@ -74723,7 +75354,11 @@
|
|
|
74723
75354
|
if (requiredRunnerTokens.length === 0) {
|
|
74724
75355
|
return true;
|
|
74725
75356
|
}
|
|
74726
|
-
const normalizedRunnerNames = [
|
|
75357
|
+
const normalizedRunnerNames = [
|
|
75358
|
+
promptRunnerIdentity.harnessName,
|
|
75359
|
+
promptRunnerIdentity.modelName,
|
|
75360
|
+
...((_a = promptRunnerIdentity.agentReferences) !== null && _a !== void 0 ? _a : []),
|
|
75361
|
+
]
|
|
74727
75362
|
.filter((name) => name !== undefined && name.trim() !== '')
|
|
74728
75363
|
.map((name) => normalizeToKebabCase(name))
|
|
74729
75364
|
.filter((name) => name !== '');
|
|
@@ -74734,7 +75369,7 @@
|
|
|
74734
75369
|
});
|
|
74735
75370
|
}
|
|
74736
75371
|
/**
|
|
74737
|
-
* Extracts model and
|
|
75372
|
+
* Extracts model, harness and Book-agent tokens from a prompt status line.
|
|
74738
75373
|
*/
|
|
74739
75374
|
function extractPromptRunnerTokens(statusLine) {
|
|
74740
75375
|
return Array.from(statusLine.matchAll(/`([^`]+)`/gu))
|
|
@@ -74749,7 +75384,7 @@
|
|
|
74749
75384
|
*
|
|
74750
75385
|
* @private internal constant of `parsePromptFile`
|
|
74751
75386
|
*/
|
|
74752
|
-
const
|
|
75387
|
+
const PROMPT_STATUS_LINE_PATTERN = /^\[(?<marker> |-|\.|[xX]|\^|!)\](?<details>.*)$/u;
|
|
74753
75388
|
/**
|
|
74754
75389
|
* Parses a prompt markdown file into sections and metadata.
|
|
74755
75390
|
*/
|
|
@@ -74773,7 +75408,7 @@
|
|
|
74773
75408
|
if (firstNonEmptyLine !== undefined) {
|
|
74774
75409
|
const statusLine = (lines[firstNonEmptyLine] || '').trim();
|
|
74775
75410
|
const parsedStatus = parseStatusLine(statusLine);
|
|
74776
|
-
const status = (_a = parsedStatus === null || parsedStatus === void 0 ? void 0 : parsedStatus.status) !== null && _a !== void 0 ? _a : (
|
|
75411
|
+
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');
|
|
74777
75412
|
const priority = (_b = parsedStatus === null || parsedStatus === void 0 ? void 0 : parsedStatus.priority) !== null && _b !== void 0 ? _b : 0;
|
|
74778
75413
|
sections.push({
|
|
74779
75414
|
index,
|
|
@@ -74801,51 +75436,47 @@
|
|
|
74801
75436
|
* For [x] done, [!] failed and [^] in-progress prompts, allow metadata after the status marker.
|
|
74802
75437
|
*/
|
|
74803
75438
|
function parseStatusLine(line) {
|
|
74804
|
-
var _a, _b, _c, _d;
|
|
74805
|
-
|
|
74806
|
-
const
|
|
74807
|
-
|
|
75439
|
+
var _a, _b, _c, _d, _e;
|
|
75440
|
+
const statusLineMatch = line.match(PROMPT_STATUS_LINE_PATTERN);
|
|
75441
|
+
const marker = (_a = statusLineMatch === null || statusLineMatch === void 0 ? void 0 : statusLineMatch.groups) === null || _a === void 0 ? void 0 : _a.marker;
|
|
75442
|
+
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 : '';
|
|
75443
|
+
if (marker === 'x' || marker === 'X') {
|
|
75444
|
+
// For done prompts [x], allow any content after (for cost/time metadata).
|
|
74808
75445
|
return { status: 'done', priority: 0 };
|
|
74809
75446
|
}
|
|
74810
|
-
|
|
74811
|
-
|
|
74812
|
-
if (failedMatch) {
|
|
75447
|
+
if (marker === '!') {
|
|
75448
|
+
// For failed prompts [!], allow any content after (for failure metadata).
|
|
74813
75449
|
return { status: 'failed', priority: 0 };
|
|
74814
75450
|
}
|
|
74815
|
-
|
|
74816
|
-
|
|
74817
|
-
if (inProgressMatch) {
|
|
75451
|
+
if (marker === '^') {
|
|
75452
|
+
// For in-progress prompts [^], allow any content after (for the steps recorded so far).
|
|
74818
75453
|
return { status: 'in-progress', priority: 0 };
|
|
74819
75454
|
}
|
|
74820
|
-
//
|
|
74821
|
-
if (
|
|
75455
|
+
// Treat [.] as the alternative spelling of not-ready [-], preserving the historical clean-line syntax.
|
|
75456
|
+
if ((marker === '-' || marker === '.') && /^[!\s]*$/u.test(details)) {
|
|
74822
75457
|
return { status: 'not-ready', priority: 0 };
|
|
74823
75458
|
}
|
|
74824
|
-
|
|
74825
|
-
// before or after those tokens. Other trailing text remains an invalid status line.
|
|
74826
|
-
const todoMatch = line.match(/^\[ \](?<details>.*)$/u);
|
|
74827
|
-
if (!todoMatch) {
|
|
75459
|
+
if (marker !== ' ') {
|
|
74828
75460
|
return undefined;
|
|
74829
75461
|
}
|
|
74830
|
-
|
|
75462
|
+
// Todo [ ] may contain backtick-delimited model/harness tokens and priority markers
|
|
75463
|
+
// before or after those tokens. Other trailing text remains an invalid status line.
|
|
74831
75464
|
const isPriorityOnly = /^[!\s]*$/u.test(details);
|
|
74832
75465
|
const hasPromptRunnerTokens = extractPromptRunnerTokens(line).length > 0;
|
|
74833
75466
|
if (details.trim() !== '' && !isPriorityOnly && !hasPromptRunnerTokens) {
|
|
74834
75467
|
return undefined;
|
|
74835
75468
|
}
|
|
74836
|
-
return { status: 'todo', priority: (
|
|
75469
|
+
return { status: 'todo', priority: (_e = (_d = details.match(/!/gu)) === null || _d === void 0 ? void 0 : _d.length) !== null && _e !== void 0 ? _e : 0 };
|
|
74837
75470
|
}
|
|
75471
|
+
|
|
74838
75472
|
/**
|
|
74839
|
-
*
|
|
75473
|
+
* HTML comment which excludes a Markdown file from all `ptbk coder` queues.
|
|
74840
75474
|
*
|
|
74841
|
-
* @private internal
|
|
75475
|
+
* @private internal constant of `loadPromptFiles`
|
|
74842
75476
|
*/
|
|
74843
|
-
|
|
74844
|
-
return PROMPT_STATUS_MARKER_PATTERN.test(line);
|
|
74845
|
-
}
|
|
74846
|
-
|
|
75477
|
+
const PTBK_CODER_IGNORE_MARKER = '<!--ptbk-coder-ignore-->';
|
|
74847
75478
|
/**
|
|
74848
|
-
* Loads and parses prompt files from the prompts directory.
|
|
75479
|
+
* Loads and parses prompt files from the prompts directory, excluding files marked for `ptbk coder` to ignore.
|
|
74849
75480
|
*/
|
|
74850
75481
|
async function loadPromptFiles(promptsDir) {
|
|
74851
75482
|
const entries = await promises.readdir(promptsDir, { withFileTypes: true });
|
|
@@ -74856,6 +75487,9 @@
|
|
|
74856
75487
|
const promptFiles = [];
|
|
74857
75488
|
for (const filePath of files) {
|
|
74858
75489
|
const content = await promises.readFile(filePath, 'utf-8');
|
|
75490
|
+
if (content.includes(PTBK_CODER_IGNORE_MARKER)) {
|
|
75491
|
+
continue;
|
|
75492
|
+
}
|
|
74859
75493
|
promptFiles.push(parsePromptFile(filePath, content));
|
|
74860
75494
|
}
|
|
74861
75495
|
return promptFiles;
|
|
@@ -74965,6 +75599,77 @@
|
|
|
74965
75599
|
findUnwrittenPrompts: findUnwrittenPrompts
|
|
74966
75600
|
});
|
|
74967
75601
|
|
|
75602
|
+
/**
|
|
75603
|
+
* Reads an optional agent `.book` file and prepares the references that route prompts to it.
|
|
75604
|
+
*
|
|
75605
|
+
* Returns `undefined` when no agent path is provided.
|
|
75606
|
+
*/
|
|
75607
|
+
async function resolveCoderAgentBook(agentBookReference, currentWorkingDirectory) {
|
|
75608
|
+
const normalizedAgentBookReference = agentBookReference === null || agentBookReference === void 0 ? void 0 : agentBookReference.trim();
|
|
75609
|
+
if (!normalizedAgentBookReference) {
|
|
75610
|
+
return undefined;
|
|
75611
|
+
}
|
|
75612
|
+
const resolvedAgentBookPath = path.resolve(currentWorkingDirectory, normalizedAgentBookReference);
|
|
75613
|
+
const agentSource = (await promises.readFile(resolvedAgentBookPath, 'utf-8').catch((error) => {
|
|
75614
|
+
if (error.code === 'ENOENT' || error.code === 'EISDIR') {
|
|
75615
|
+
throw new NotFoundError(spaceTrim(`
|
|
75616
|
+
Agent book \`${normalizedAgentBookReference}\` was not found or is not a file.
|
|
75617
|
+
|
|
75618
|
+
Pass a path to a \`.book\` file in \`--agent\`.
|
|
75619
|
+
`));
|
|
75620
|
+
}
|
|
75621
|
+
throw error;
|
|
75622
|
+
}));
|
|
75623
|
+
return {
|
|
75624
|
+
agentSource,
|
|
75625
|
+
agentReferences: createCoderAgentReferences({
|
|
75626
|
+
agentBookReference: normalizedAgentBookReference,
|
|
75627
|
+
resolvedAgentBookPath,
|
|
75628
|
+
currentWorkingDirectory,
|
|
75629
|
+
agentSource,
|
|
75630
|
+
}),
|
|
75631
|
+
};
|
|
75632
|
+
}
|
|
75633
|
+
/**
|
|
75634
|
+
* Reads an optional agent `.book` file and compiles its system message for injection into coder prompts.
|
|
75635
|
+
*
|
|
75636
|
+
* Returns `undefined` when no agent path is provided.
|
|
75637
|
+
*/
|
|
75638
|
+
async function resolveCoderAgent(agentBookReference, currentWorkingDirectory) {
|
|
75639
|
+
const resolvedAgentBook = await resolveCoderAgentBook(agentBookReference, currentWorkingDirectory);
|
|
75640
|
+
if (resolvedAgentBook === undefined) {
|
|
75641
|
+
return undefined;
|
|
75642
|
+
}
|
|
75643
|
+
return {
|
|
75644
|
+
...resolvedAgentBook,
|
|
75645
|
+
systemMessage: await createAgentRunnerSystemMessage(resolvedAgentBook.agentSource),
|
|
75646
|
+
};
|
|
75647
|
+
}
|
|
75648
|
+
/**
|
|
75649
|
+
* Creates the path and Book-title aliases which a prompt can use to target one selected agent.
|
|
75650
|
+
*
|
|
75651
|
+
* @private internal utility of `resolveCoderAgentBook`
|
|
75652
|
+
*/
|
|
75653
|
+
function createCoderAgentReferences(options) {
|
|
75654
|
+
const relativeAgentBookPath = path.relative(options.currentWorkingDirectory, options.resolvedAgentBookPath).replaceAll('\\', '/');
|
|
75655
|
+
const agentBookFileName = path.basename(options.resolvedAgentBookPath);
|
|
75656
|
+
const agentBookName = path.basename(options.resolvedAgentBookPath, path.extname(options.resolvedAgentBookPath));
|
|
75657
|
+
const agentNameFromBook = parseAgentSource(options.agentSource).agentName;
|
|
75658
|
+
return Array.from(new Set([
|
|
75659
|
+
options.agentBookReference,
|
|
75660
|
+
relativeAgentBookPath,
|
|
75661
|
+
agentBookFileName,
|
|
75662
|
+
agentBookName,
|
|
75663
|
+
agentNameFromBook,
|
|
75664
|
+
].filter((agentReference) => agentReference.trim() !== '')));
|
|
75665
|
+
}
|
|
75666
|
+
|
|
75667
|
+
var resolveCoderAgent$1 = /*#__PURE__*/Object.freeze({
|
|
75668
|
+
__proto__: null,
|
|
75669
|
+
resolveCoderAgentBook: resolveCoderAgentBook,
|
|
75670
|
+
resolveCoderAgent: resolveCoderAgent
|
|
75671
|
+
});
|
|
75672
|
+
|
|
74968
75673
|
/**
|
|
74969
75674
|
* Lists todo prompts that are ready to run (no authoring placeholders).
|
|
74970
75675
|
*/
|
|
@@ -75047,23 +75752,6 @@
|
|
|
75047
75752
|
listCoderPrompts: listCoderPrompts
|
|
75048
75753
|
});
|
|
75049
75754
|
|
|
75050
|
-
/**
|
|
75051
|
-
* Formats one unknown error-like value into its readable message without the stack trace.
|
|
75052
|
-
*
|
|
75053
|
-
* Use this instead of `formatUnknownErrorDetails` whenever the text is shown to the user, for example
|
|
75054
|
-
* inside a branded error, where the stack of the wrapped error would only bury the actual cause.
|
|
75055
|
-
*/
|
|
75056
|
-
function formatUnknownErrorMessage(error) {
|
|
75057
|
-
if (error instanceof Error) {
|
|
75058
|
-
return error.message;
|
|
75059
|
-
}
|
|
75060
|
-
if (typeof error === 'string') {
|
|
75061
|
-
return error;
|
|
75062
|
-
}
|
|
75063
|
-
const serializedError = JSON.stringify(error, null, 2);
|
|
75064
|
-
return serializedError !== null && serializedError !== void 0 ? serializedError : String(error);
|
|
75065
|
-
}
|
|
75066
|
-
|
|
75067
75755
|
/**
|
|
75068
75756
|
* Builds a normalized temporary shell script path for prompt runners.
|
|
75069
75757
|
*/
|
|
@@ -75362,7 +76050,7 @@
|
|
|
75362
76050
|
/**
|
|
75363
76051
|
* CLI usage text for this script.
|
|
75364
76052
|
*/
|
|
75365
|
-
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]';
|
|
76053
|
+
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]';
|
|
75366
76054
|
/**
|
|
75367
76055
|
* Top-level flags supported by this command.
|
|
75368
76056
|
*/
|
|
@@ -75370,6 +76058,7 @@
|
|
|
75370
76058
|
'--dry-run',
|
|
75371
76059
|
'--harness',
|
|
75372
76060
|
'--model',
|
|
76061
|
+
'--agent',
|
|
75373
76062
|
'--context',
|
|
75374
76063
|
'--test',
|
|
75375
76064
|
'--test-before',
|
|
@@ -75408,6 +76097,7 @@
|
|
|
75408
76097
|
}
|
|
75409
76098
|
}
|
|
75410
76099
|
const model = readOptionValue(args, '--model');
|
|
76100
|
+
const agent = readOptionValue(args, '--agent');
|
|
75411
76101
|
const context = readOptionValue(args, '--context');
|
|
75412
76102
|
const hasTestCommandFlag = args.includes('--test');
|
|
75413
76103
|
const testCommand = readVariadicOptionValue(args, '--test');
|
|
@@ -75484,6 +76174,7 @@
|
|
|
75484
76174
|
noUi,
|
|
75485
76175
|
agentName,
|
|
75486
76176
|
model,
|
|
76177
|
+
agent,
|
|
75487
76178
|
context,
|
|
75488
76179
|
testCommand,
|
|
75489
76180
|
testBefore,
|
|
@@ -75918,30 +76609,43 @@
|
|
|
75918
76609
|
// Note: [🟡] Code in this file is only used from `@promptbook/cli` orchestration scripts and is not shipped to other consumers.
|
|
75919
76610
|
|
|
75920
76611
|
/**
|
|
75921
|
-
*
|
|
76612
|
+
* Creates the guard which watches the free disk space while one `ptbk coder` run is in progress.
|
|
75922
76613
|
*
|
|
75923
|
-
*
|
|
76614
|
+
* The guard runs at every pause checkpoint of the run. When the disk became critically full it reports the
|
|
76615
|
+
* warning and requests a pause, so the run stops at that checkpoint instead of failing in the middle of a
|
|
76616
|
+
* coding round, and continues once the user has freed some space and pressed `P`.
|
|
76617
|
+
*
|
|
76618
|
+
* @private internal utility of `ptbk coder` free disk space handling
|
|
75924
76619
|
*/
|
|
75925
|
-
|
|
75926
|
-
|
|
75927
|
-
|
|
75928
|
-
|
|
75929
|
-
|
|
75930
|
-
|
|
75931
|
-
|
|
75932
|
-
|
|
75933
|
-
|
|
76620
|
+
function createFreeDiskSpaceGuard(options) {
|
|
76621
|
+
const { inspectedPath, isAskingQuestionsEnabled } = options;
|
|
76622
|
+
let lastMeasurementTimeMs;
|
|
76623
|
+
return async () => {
|
|
76624
|
+
if (lastMeasurementTimeMs !== undefined &&
|
|
76625
|
+
Date.now() - lastMeasurementTimeMs < FREE_DISK_SPACE_RECHECK_INTERVAL_MS) {
|
|
76626
|
+
return;
|
|
76627
|
+
}
|
|
76628
|
+
lastMeasurementTimeMs = Date.now();
|
|
76629
|
+
const freeDiskSpaceStatus = await $readFreeDiskSpaceStatus(inspectedPath);
|
|
76630
|
+
if (freeDiskSpaceStatus === null || freeDiskSpaceStatus.level !== 'critical') {
|
|
76631
|
+
return;
|
|
76632
|
+
}
|
|
76633
|
+
console.warn(colors__default["default"].yellow(_spaceTrim.spaceTrim((block) => `
|
|
76634
|
+
The disk is running out of space while \`ptbk coder\` is working.
|
|
75934
76635
|
|
|
75935
|
-
|
|
75936
|
-
|
|
76636
|
+
${block(formatLowFreeDiskSpaceWarning(freeDiskSpaceStatus))}
|
|
76637
|
+
- Press \`P\` to continue once the disk space is freed, or start the run with \`--no-questions\` to never pause on a full disk.
|
|
76638
|
+
`)));
|
|
76639
|
+
if (!isAskingQuestionsEnabled) {
|
|
76640
|
+
// Note: `--no-questions` forbids stopping and waiting for somebody who would free the disk space,
|
|
76641
|
+
// so the run keeps going and the warning above is the only thing which is reported
|
|
76642
|
+
return;
|
|
75937
76643
|
}
|
|
75938
|
-
|
|
75939
|
-
|
|
75940
|
-
return {
|
|
75941
|
-
agentSource: agentSource,
|
|
75942
|
-
systemMessage: await createAgentRunnerSystemMessage(agentSource),
|
|
76644
|
+
announcePauseTargetLabel(`continuing with only ${formatFreeDiskSpaceBytes(freeDiskSpaceStatus.availableBytes)} of free disk space left`);
|
|
76645
|
+
requestPause();
|
|
75943
76646
|
};
|
|
75944
76647
|
}
|
|
76648
|
+
// 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`
|
|
75945
76649
|
|
|
75946
76650
|
/**
|
|
75947
76651
|
* Refresh interval used by the countdown display while waiting.
|
|
@@ -77912,6 +78616,169 @@
|
|
|
77912
78616
|
await promises.writeFile(file.path, content, 'utf-8');
|
|
77913
78617
|
}
|
|
77914
78618
|
|
|
78619
|
+
/**
|
|
78620
|
+
* Creates a safe markdown fenced code block even when content contains backticks.
|
|
78621
|
+
*
|
|
78622
|
+
* @param content - Raw code content.
|
|
78623
|
+
* @param language - Optional info-string language label.
|
|
78624
|
+
* @returns Fenced code block.
|
|
78625
|
+
*
|
|
78626
|
+
* @private internal utility of `createStandaloneBookLanguageMarkdown` and of the `ptbk coder` run traces
|
|
78627
|
+
*/
|
|
78628
|
+
function getSafeCodeBlock(content, language = 'markdown') {
|
|
78629
|
+
const maxBacktickCount = Math.max(0, ...(content.match(/`+/g) || []).map((match) => match.length));
|
|
78630
|
+
const fence = '`'.repeat(Math.max(3, maxBacktickCount + 1));
|
|
78631
|
+
return `${fence}${language}\n${content}\n${fence}`;
|
|
78632
|
+
}
|
|
78633
|
+
|
|
78634
|
+
/**
|
|
78635
|
+
* Renders the markdown run trace of one finished or failed prompt round.
|
|
78636
|
+
*
|
|
78637
|
+
* The trace pairs the metadata of the round - which harness, model and thinking level ran it, how long each of
|
|
78638
|
+
* its steps took and what it cost - with the untouched runtime log, so a finished round can still be analyzed
|
|
78639
|
+
* after its temporary artifacts are cleaned up.
|
|
78640
|
+
*/
|
|
78641
|
+
function buildPromptRunTraceContent(options) {
|
|
78642
|
+
const sections = [
|
|
78643
|
+
buildPromptRunTraceSummarySection(options),
|
|
78644
|
+
buildPromptRunTraceFailureSection(options.outcome),
|
|
78645
|
+
buildPromptRunTraceRuntimeLogSection(options.runtimeLog),
|
|
78646
|
+
].filter((section) => section !== undefined);
|
|
78647
|
+
return `${sections.join('\n\n')}\n`;
|
|
78648
|
+
}
|
|
78649
|
+
/**
|
|
78650
|
+
* Renders the heading and the metadata bullet list of one run trace.
|
|
78651
|
+
*/
|
|
78652
|
+
function buildPromptRunTraceSummarySection(options) {
|
|
78653
|
+
const { file, section, outcome } = options;
|
|
78654
|
+
const runnerSignature = formatRunnerSignature(options.runnerName, options.modelName, options.thinkingLevel);
|
|
78655
|
+
const loginMethodLabel = outcome.kind === 'succeeded' ? formatCodexLoginMethod(outcome.loginMethod) : undefined;
|
|
78656
|
+
const loginMethodSuffix = loginMethodLabel ? ` (${loginMethodLabel})` : '';
|
|
78657
|
+
const detailLines = [
|
|
78658
|
+
`- **Prompt:** ${buildPromptSummary(file, section)}`,
|
|
78659
|
+
...buildPromptRunTraceSectionLines(file, section),
|
|
78660
|
+
`- **Outcome:** ${formatPromptRunTraceOutcomeLabel(outcome)}`,
|
|
78661
|
+
`- **Runner:** ${runnerSignature}${loginMethodSuffix}`,
|
|
78662
|
+
`- **Attempts:** ${options.attemptCount}`,
|
|
78663
|
+
...buildPromptRunTraceStepsLines(outcome),
|
|
78664
|
+
...buildPromptRunTraceTestCommandLines(options.testCommand),
|
|
78665
|
+
`- **Started:** ${options.startedDate.toISOString()}`,
|
|
78666
|
+
`- **Finished:** ${options.finishedDate.toISOString()}`,
|
|
78667
|
+
`- **Duration:** ${moment__default["default"].duration(options.finishedDate.diff(options.startedDate)).humanize()}`,
|
|
78668
|
+
];
|
|
78669
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
78670
|
+
# Run trace of \`${buildPromptLabelForDisplay(file, section)}\`
|
|
78671
|
+
|
|
78672
|
+
${block(detailLines.join('\n'))}
|
|
78673
|
+
`);
|
|
78674
|
+
}
|
|
78675
|
+
/**
|
|
78676
|
+
* Renders which section of its prompt file the round implemented.
|
|
78677
|
+
*
|
|
78678
|
+
* A prompt file holding exactly one section says nothing by naming it, exactly like the section suffix of its
|
|
78679
|
+
* generated artifact names, so only a file with more than one section reports the section it traced.
|
|
78680
|
+
*/
|
|
78681
|
+
function buildPromptRunTraceSectionLines(file, section) {
|
|
78682
|
+
if (file.sections.length <= 1) {
|
|
78683
|
+
return [];
|
|
78684
|
+
}
|
|
78685
|
+
return [`- **Prompt section:** ${section.index + 1} of ${file.sections.length}`];
|
|
78686
|
+
}
|
|
78687
|
+
/**
|
|
78688
|
+
* Renders the per-step usage breakdown of a successful round, omitted for a round which never finished one.
|
|
78689
|
+
*/
|
|
78690
|
+
function buildPromptRunTraceStepsLines(outcome) {
|
|
78691
|
+
if (outcome.kind !== 'succeeded') {
|
|
78692
|
+
return [];
|
|
78693
|
+
}
|
|
78694
|
+
const stepsSummary = formatCoderRunSteps(outcome.steps);
|
|
78695
|
+
if (stepsSummary === '') {
|
|
78696
|
+
return [];
|
|
78697
|
+
}
|
|
78698
|
+
return [`- **Steps:** ${stepsSummary}`];
|
|
78699
|
+
}
|
|
78700
|
+
/**
|
|
78701
|
+
* Renders the verification command of the round, omitted when the round ran without one.
|
|
78702
|
+
*/
|
|
78703
|
+
function buildPromptRunTraceTestCommandLines(testCommand) {
|
|
78704
|
+
if (!testCommand) {
|
|
78705
|
+
return [];
|
|
78706
|
+
}
|
|
78707
|
+
return [`- **Verification command:** \`${testCommand}\``];
|
|
78708
|
+
}
|
|
78709
|
+
/**
|
|
78710
|
+
* Renders the failure details of a failed round, omitted for a successful one.
|
|
78711
|
+
*/
|
|
78712
|
+
function buildPromptRunTraceFailureSection(outcome) {
|
|
78713
|
+
if (outcome.kind !== 'failed') {
|
|
78714
|
+
return undefined;
|
|
78715
|
+
}
|
|
78716
|
+
return `## Failure\n\n${getSafeCodeBlock(formatUnknownErrorDetails(outcome.error), 'text')}`;
|
|
78717
|
+
}
|
|
78718
|
+
/**
|
|
78719
|
+
* Renders the untouched runtime log of the round, or says that the round produced none.
|
|
78720
|
+
*/
|
|
78721
|
+
function buildPromptRunTraceRuntimeLogSection(runtimeLog) {
|
|
78722
|
+
if (runtimeLog.trim() === '') {
|
|
78723
|
+
return '## Runtime log\n\n_This round has produced no readable runtime log._';
|
|
78724
|
+
}
|
|
78725
|
+
return `## Runtime log\n\n${getSafeCodeBlock(runtimeLog.replace(/\r\n/gu, '\n').trimEnd(), 'text')}`;
|
|
78726
|
+
}
|
|
78727
|
+
/**
|
|
78728
|
+
* Formats the outcome of the round as the human-readable label of its trace.
|
|
78729
|
+
*/
|
|
78730
|
+
function formatPromptRunTraceOutcomeLabel(outcome) {
|
|
78731
|
+
return outcome.kind === 'succeeded' ? 'Succeeded' : 'Failed';
|
|
78732
|
+
}
|
|
78733
|
+
|
|
78734
|
+
/**
|
|
78735
|
+
* Name of the directory which keeps the run traces inside the prompts directory.
|
|
78736
|
+
*/
|
|
78737
|
+
const PROMPT_RUN_TRACES_DIRECTORY_NAME = 'traces';
|
|
78738
|
+
/**
|
|
78739
|
+
* Builds the path of the run trace which belongs to one prompt section.
|
|
78740
|
+
*
|
|
78741
|
+
* The trace is stored in the `traces` directory of the very same prompts directory the prompt itself lives in,
|
|
78742
|
+
* and it carries the name of its prompt file. A prompt file holding more than one section appends the section
|
|
78743
|
+
* suffix, exactly like the temporary scripts and the isolation worktrees of the same section do.
|
|
78744
|
+
*/
|
|
78745
|
+
function buildPromptRunTracePath(file, section) {
|
|
78746
|
+
const promptFileBaseName = file.name.replace(/\.[^.]+$/u, '');
|
|
78747
|
+
const traceFileName = `${promptFileBaseName}${buildPromptSectionSuffix(file, section)}.md`;
|
|
78748
|
+
return path.join(path.dirname(file.path), PROMPT_RUN_TRACES_DIRECTORY_NAME, traceFileName);
|
|
78749
|
+
}
|
|
78750
|
+
|
|
78751
|
+
/**
|
|
78752
|
+
* Writes the run trace of one prompt round into the `traces` directory of the prompts directory.
|
|
78753
|
+
*
|
|
78754
|
+
* Returns the path of the written trace so callers can include it in a commit.
|
|
78755
|
+
*/
|
|
78756
|
+
async function writePromptRunTrace(options) {
|
|
78757
|
+
const { logPath, ...contentOptions } = options;
|
|
78758
|
+
const tracePath = buildPromptRunTracePath(options.file, options.section);
|
|
78759
|
+
const runtimeLog = await readPromptRuntimeLog(logPath);
|
|
78760
|
+
await promises.mkdir(path.dirname(tracePath), { recursive: true });
|
|
78761
|
+
await promises.writeFile(tracePath, buildPromptRunTraceContent({ ...contentOptions, runtimeLog }), 'utf-8');
|
|
78762
|
+
return tracePath;
|
|
78763
|
+
}
|
|
78764
|
+
/**
|
|
78765
|
+
* Reads the live runtime log of one round.
|
|
78766
|
+
*
|
|
78767
|
+
* A round which never produced a readable log still gets its trace, because the metadata of the round is worth
|
|
78768
|
+
* keeping on its own - so a missing log is reported as empty instead of failing the round which has just passed.
|
|
78769
|
+
*/
|
|
78770
|
+
async function readPromptRuntimeLog(logPath) {
|
|
78771
|
+
if (!logPath) {
|
|
78772
|
+
return '';
|
|
78773
|
+
}
|
|
78774
|
+
try {
|
|
78775
|
+
return await promises.readFile(logPath, 'utf-8');
|
|
78776
|
+
}
|
|
78777
|
+
catch (_a) {
|
|
78778
|
+
return '';
|
|
78779
|
+
}
|
|
78780
|
+
}
|
|
78781
|
+
|
|
77915
78782
|
/**
|
|
77916
78783
|
* Refreshes optional harness subscription usage in the shared coder-run UI state.
|
|
77917
78784
|
*
|
|
@@ -78034,7 +78901,9 @@
|
|
|
78034
78901
|
catch (error) {
|
|
78035
78902
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
78036
78903
|
lastError = error;
|
|
78037
|
-
|
|
78904
|
+
// Note: A harness which is not logged in answers every retry the same way, so the user gets
|
|
78905
|
+
// the sign-in instructions right away instead of after every retry has waited its delay
|
|
78906
|
+
if (error instanceof AuthenticationError || errorRetryAttempt >= MAX_RETRY_ATTEMPTS_AFTER_ERROR) {
|
|
78038
78907
|
break;
|
|
78039
78908
|
}
|
|
78040
78909
|
await waitAfterErrorBeforeRetry({
|
|
@@ -78056,6 +78925,7 @@
|
|
|
78056
78925
|
attemptCount,
|
|
78057
78926
|
error: lastError,
|
|
78058
78927
|
options,
|
|
78928
|
+
logPath,
|
|
78059
78929
|
roundCommitScope,
|
|
78060
78930
|
uiHandle,
|
|
78061
78931
|
waitForRequestedPause,
|
|
@@ -78172,6 +79042,17 @@
|
|
|
78172
79042
|
// Note: The prompt status is always written into the original project, an isolated round transports
|
|
78173
79043
|
// its own changes back through the merge instead
|
|
78174
79044
|
await writePromptFile(nextPrompt.file);
|
|
79045
|
+
// Note: Written before the round is committed, so the trace of the round lands in the very same commit
|
|
79046
|
+
// as the prompt it describes, and before the live runtime log it is built from is deleted
|
|
79047
|
+
await recordPromptRoundTrace({
|
|
79048
|
+
options: runOptions,
|
|
79049
|
+
nextPrompt,
|
|
79050
|
+
runnerMetadata,
|
|
79051
|
+
promptExecutionStartedDate,
|
|
79052
|
+
attemptCount: result.attemptCount,
|
|
79053
|
+
logPath,
|
|
79054
|
+
outcome: { kind: 'succeeded', steps: result.steps, loginMethod: result.loginMethod },
|
|
79055
|
+
});
|
|
78175
79056
|
await normalizeLineEndingsForCurrentRound(runOptions, roundProjectPath, roundCommitScope);
|
|
78176
79057
|
await recordPromptDurationInEstimateCache({
|
|
78177
79058
|
options: runOptions,
|
|
@@ -78219,7 +79100,7 @@
|
|
|
78219
79100
|
* Finalizes a failed prompt round, persisting prompt failure metadata before rethrowing.
|
|
78220
79101
|
*/
|
|
78221
79102
|
async function finalizeFailedPromptRound(options) {
|
|
78222
|
-
const { nextPrompt, runnerMetadata, previousRunnerSignatures, promptExecutionStartedDate, attemptCount, error, options: runOptions, roundCommitScope, uiHandle, waitForRequestedPause, roundProjectPath, } = options;
|
|
79103
|
+
const { nextPrompt, runnerMetadata, previousRunnerSignatures, promptExecutionStartedDate, attemptCount, error, options: runOptions, logPath, roundCommitScope, uiHandle, waitForRequestedPause, roundProjectPath, } = options;
|
|
78223
79104
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
78224
79105
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('error');
|
|
78225
79106
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(error instanceof Error ? error.message : String(error));
|
|
@@ -78245,8 +79126,42 @@
|
|
|
78245
79126
|
modelName: runnerMetadata.modelName,
|
|
78246
79127
|
error,
|
|
78247
79128
|
});
|
|
79129
|
+
// Note: A failed round is exactly the round whose trace is worth reading, so it is written before the live
|
|
79130
|
+
// runtime log it is built from is deleted
|
|
79131
|
+
await recordPromptRoundTrace({
|
|
79132
|
+
options: runOptions,
|
|
79133
|
+
nextPrompt,
|
|
79134
|
+
runnerMetadata,
|
|
79135
|
+
promptExecutionStartedDate,
|
|
79136
|
+
attemptCount,
|
|
79137
|
+
logPath,
|
|
79138
|
+
outcome: { kind: 'failed', error },
|
|
79139
|
+
});
|
|
78248
79140
|
await normalizeLineEndingsForCurrentRound(runOptions, roundProjectPath, roundCommitScope);
|
|
78249
79141
|
}
|
|
79142
|
+
/**
|
|
79143
|
+
* Persists the run trace of one prompt round, so the round can still be analyzed after its temporary
|
|
79144
|
+
* artifacts are gone.
|
|
79145
|
+
*
|
|
79146
|
+
* This is the single place where both the successful and the failed round record what they did, which harness,
|
|
79147
|
+
* model and thinking level did it and everything that harness has written while doing it.
|
|
79148
|
+
*/
|
|
79149
|
+
async function recordPromptRoundTrace(options) {
|
|
79150
|
+
const { options: runOptions, nextPrompt, runnerMetadata, promptExecutionStartedDate, attemptCount, logPath, outcome, } = options;
|
|
79151
|
+
await writePromptRunTrace({
|
|
79152
|
+
file: nextPrompt.file,
|
|
79153
|
+
section: nextPrompt.section,
|
|
79154
|
+
runnerName: runnerMetadata.runnerName,
|
|
79155
|
+
modelName: runnerMetadata.modelName,
|
|
79156
|
+
thinkingLevel: runOptions.thinkingLevel,
|
|
79157
|
+
testCommand: runOptions.testCommand,
|
|
79158
|
+
attemptCount,
|
|
79159
|
+
startedDate: promptExecutionStartedDate,
|
|
79160
|
+
finishedDate: moment__default["default"](),
|
|
79161
|
+
outcome,
|
|
79162
|
+
logPath,
|
|
79163
|
+
});
|
|
79164
|
+
}
|
|
78250
79165
|
/**
|
|
78251
79166
|
* Waits for the optional user confirmation immediately before creating the commit.
|
|
78252
79167
|
*/
|
|
@@ -78895,7 +79810,13 @@
|
|
|
78895
79810
|
await commitChanges(buildCoderIsolationMergeFailureCommitMessage(worktree), {
|
|
78896
79811
|
autoPush: options.options.autoPush,
|
|
78897
79812
|
projectPath: worktree.projectPath,
|
|
78898
|
-
|
|
79813
|
+
// Note: The round itself has already succeeded, so it has left its run trace in the original project.
|
|
79814
|
+
// It belongs to this commit, which is the only one this task still gets.
|
|
79815
|
+
relevantPaths: [
|
|
79816
|
+
nextPrompt.file.path,
|
|
79817
|
+
errorLogPath,
|
|
79818
|
+
buildPromptRunTracePath(nextPrompt.file, nextPrompt.section),
|
|
79819
|
+
].map((path) => toProjectRelativeGitPath(worktree.projectPath, path)),
|
|
78899
79820
|
});
|
|
78900
79821
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(mergeFailureError.message);
|
|
78901
79822
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Merging \`${worktree.taskName}\` failed, worktree kept for a manual merge`);
|
|
@@ -79170,12 +80091,23 @@
|
|
|
79170
80091
|
* @public exported from `@promptbook/cli`
|
|
79171
80092
|
*/
|
|
79172
80093
|
async function runCodexPrompts(providedOptions) {
|
|
80094
|
+
var _a;
|
|
79173
80095
|
const options = normalizeRunOptions(providedOptions !== null && providedOptions !== void 0 ? providedOptions : parseRunOptions(process.argv.slice(2)));
|
|
79174
80096
|
validateRunCodexPromptOptions(options);
|
|
79175
80097
|
resetCoderRunControls();
|
|
79176
80098
|
const runStartDate = moment__default["default"]();
|
|
79177
80099
|
const { isRichUiEnabled, progressDisplay, uiHandle } = createRunDisplays(options, runStartDate);
|
|
79178
|
-
const waitForRequestedPause = createPauseWaiter({
|
|
80100
|
+
const waitForRequestedPause = createPauseWaiter({
|
|
80101
|
+
isRichUiEnabled,
|
|
80102
|
+
progressDisplay,
|
|
80103
|
+
uiHandle,
|
|
80104
|
+
// Note: Every pause checkpoint of the whole run goes through this one waiter, so watching the free disk
|
|
80105
|
+
// space here covers each round, each verification and each runner without repeating the check
|
|
80106
|
+
guardFreeDiskSpace: createFreeDiskSpaceGuard({
|
|
80107
|
+
inspectedPath: process.cwd(),
|
|
80108
|
+
isAskingQuestionsEnabled: (_a = options.isAskingQuestionsEnabled) !== null && _a !== void 0 ? _a : true,
|
|
80109
|
+
}),
|
|
80110
|
+
});
|
|
79179
80111
|
startPauseListenerIfNeeded(isRichUiEnabled);
|
|
79180
80112
|
try {
|
|
79181
80113
|
const resolvedCoderContext = await resolveCoderContext(options.context, process.cwd());
|
|
@@ -79188,6 +80120,7 @@
|
|
|
79188
80120
|
const promptRunnerIdentity = {
|
|
79189
80121
|
harnessName: options.agentName,
|
|
79190
80122
|
modelName: actualRunnerModel,
|
|
80123
|
+
agentReferences: resolvedCoderAgent === null || resolvedCoderAgent === void 0 ? void 0 : resolvedCoderAgent.agentReferences,
|
|
79191
80124
|
};
|
|
79192
80125
|
console.info(colors__default["default"].green(`Running prompts with ${runner.name}`));
|
|
79193
80126
|
initializeRunUi(uiHandle, runner.name, actualRunnerModel, options);
|
|
@@ -79624,11 +80557,14 @@
|
|
|
79624
80557
|
* Creates a pause waiter that keeps the progress display and rich UI in sync.
|
|
79625
80558
|
*/
|
|
79626
80559
|
function createPauseWaiter(options) {
|
|
79627
|
-
const { isRichUiEnabled, progressDisplay, uiHandle } = options;
|
|
80560
|
+
const { isRichUiEnabled, progressDisplay, uiHandle, guardFreeDiskSpace } = options;
|
|
79628
80561
|
return async (checkpoint) => {
|
|
79629
80562
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase(checkpoint.phase);
|
|
79630
80563
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(checkpoint.statusMessage);
|
|
79631
80564
|
announcePauseTargetLabel(checkpoint.checkpointLabel);
|
|
80565
|
+
// Note: Runs after the checkpoint label is announced, so a pause requested because of a full disk
|
|
80566
|
+
// replaces that label and says why the run is standing still
|
|
80567
|
+
await guardFreeDiskSpace();
|
|
79632
80568
|
await checkPause({
|
|
79633
80569
|
silent: isRichUiEnabled,
|
|
79634
80570
|
onPaused: () => {
|
|
@@ -79747,7 +80683,7 @@
|
|
|
79747
80683
|
return false;
|
|
79748
80684
|
}
|
|
79749
80685
|
if (promptQueueSnapshot.stats.forAgent > 0) {
|
|
79750
|
-
announceRunCompletion('No prompts match the selected harness or
|
|
80686
|
+
announceRunCompletion('No prompts match the selected harness, model or agent.', colors__default["default"].yellow, isRichUiEnabled, uiHandle);
|
|
79751
80687
|
}
|
|
79752
80688
|
else if (promptQueueSnapshot.stats.toBeWritten > 0) {
|
|
79753
80689
|
announceRunCompletion('No prompts ready for agent.', colors__default["default"].yellow, isRichUiEnabled, uiHandle);
|
|
@@ -79792,7 +80728,7 @@
|
|
|
79792
80728
|
function announceKeepAliveStatus(promptQueueSnapshot, isRichUiEnabled, uiHandle) {
|
|
79793
80729
|
let message;
|
|
79794
80730
|
if (promptQueueSnapshot.stats.forAgent > 0) {
|
|
79795
|
-
message = 'No prompts match the selected harness or
|
|
80731
|
+
message = 'No prompts match the selected harness, model or agent. Watching for changes...';
|
|
79796
80732
|
}
|
|
79797
80733
|
else if (promptQueueSnapshot.stats.toBeWritten > 0) {
|
|
79798
80734
|
message = 'No prompts ready for agent. Watching for changes...';
|