@promptbook/cli 0.114.0-47 → 0.114.0-49
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -25
- package/apps/agents-server/tests/e2e/mockSupabaseServer.cjs +79 -2
- package/apps/agents-server/tests/e2e/support/ChatHistoryNavigationSupport.ts +12 -2
- package/apps/agents-server/tests/e2e/support/auth.ts +6 -0
- package/esm/index.es.js +1327 -478
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-codex-prompts/checks/CheckBeforeMode.d.ts +20 -0
- package/esm/scripts/run-codex-prompts/checks/checkRepairInstructions.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/checks/createCheckBeforeRepairPrompt.d.ts +9 -0
- package/esm/scripts/run-codex-prompts/checks/limitCheckOutput.d.ts +4 -0
- package/esm/scripts/run-codex-prompts/checks/projectCheck.d.ts +26 -0
- package/esm/scripts/run-codex-prompts/checks/projectScriptReferences.d.ts +7 -0
- package/esm/scripts/run-codex-prompts/checks/runCheckBefore.d.ts +26 -0
- package/esm/scripts/run-codex-prompts/checks/runPromptCheckCommand.d.ts +16 -0
- package/esm/scripts/run-codex-prompts/{testing/runPromptWithTestFeedback.d.ts → checks/runPromptWithCheckFeedback.d.ts} +9 -9
- package/esm/scripts/run-codex-prompts/common/resolveCoderContext.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/common/resolveCoderProjectContext.d.ts +17 -0
- package/esm/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +2 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/quoteBashArgument.d.ts +2 -0
- package/esm/scripts/run-codex-prompts/isolation/mapProjectReferenceToWorktree.d.ts +5 -0
- package/esm/scripts/run-codex-prompts/main/runPromptRound.d.ts +3 -1
- package/esm/scripts/run-codex-prompts/prompts/buildPromptLabel.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/buildPromptLabelForDisplay.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/buildPromptRunTraceContent.d.ts +3 -1
- package/esm/scripts/run-codex-prompts/prompts/formatCoderRunSteps.d.ts +2 -2
- package/esm/scripts/run-codex-prompts/prompts/listUpcomingTasks.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/prompts/printPromptsToBeWritten.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +2 -0
- package/esm/scripts/run-codex-prompts/team/createCoderTeamPromptRunner.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -1
- package/esm/src/cli/cli-commands/coder/agentCliOptions.d.ts +5 -0
- package/esm/src/cli/cli-commands/coder/coderAgentRole.d.ts +5 -0
- package/esm/src/cli/cli-commands/coder/coderReferencedArtifacts.d.ts +2 -2
- package/esm/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.d.ts +3 -2
- package/esm/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/coder/findLegacyCoderCheckCallers.d.ts +5 -0
- package/esm/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +6 -0
- package/esm/src/cli/cli-commands/coder/mergeStringRecordJsonFile.d.ts +5 -3
- package/esm/src/cli/cli-commands/coder/planning/runPlanningSession.d.ts +3 -0
- package/esm/src/cli/cli-commands/coder/prepareCoderPackageJsonScripts.d.ts +12 -0
- package/esm/src/cli/cli-commands/coder.d.ts +1 -1
- package/esm/src/cli/cli-commands/common/coderCheckCliOptions.d.ts +21 -0
- package/esm/src/cli/cli-commands/common/coderCheckCliOptions.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/projectCliOptions.d.ts +30 -0
- package/esm/src/cli/cli-commands/common/projectCliOptions.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/promptbook-cli/$checkPromptbookCliInstallations.d.ts +1 -1
- package/esm/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.d.ts +1 -1
- package/esm/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.d.ts +1 -1
- package/esm/src/cli/cli-commands/common/promptbook-cli/$updatePromptbookCliInstallation.d.ts +1 -1
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/_packages/cli.readme.md +15 -0
- package/src/cli/cli-commands/agent/chat.ts +11 -2
- package/src/cli/cli-commands/agent/exec.ts +11 -2
- package/src/cli/cli-commands/agent-folder/init.ts +6 -2
- package/src/cli/cli-commands/agent-folder/initializeAgentRunnerCommand.ts +9 -2
- package/src/cli/cli-commands/coder/add.ts +7 -1
- package/src/cli/cli-commands/coder/agentCliOptions.ts +11 -1
- package/src/cli/cli-commands/coder/coderAgentRole.ts +6 -0
- package/src/cli/cli-commands/coder/coderReferencedArtifacts.ts +3 -3
- package/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.ts +22 -3
- package/src/cli/cli-commands/coder/find-fresh-emoji-tags.ts +3 -0
- package/src/cli/cli-commands/coder/find-refactor-candidates.ts +3 -0
- package/src/cli/cli-commands/coder/find-unwritten.ts +3 -0
- package/src/cli/cli-commands/coder/findLegacyCoderCheckCallers.ts +87 -0
- package/src/cli/cli-commands/coder/generate-boilerplates.ts +3 -0
- package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +6 -7
- package/src/cli/cli-commands/coder/init.ts +8 -2
- package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +16 -4
- package/src/cli/cli-commands/coder/list.ts +6 -1
- package/src/cli/cli-commands/coder/mergeStringRecordJsonFile.ts +14 -4
- package/src/cli/cli-commands/coder/ping.ts +7 -1
- package/src/cli/cli-commands/coder/plan.ts +17 -5
- package/src/cli/cli-commands/coder/planning/README.md +5 -3
- package/src/cli/cli-commands/coder/planning/fixtures/coding.cjs +22 -0
- package/src/cli/cli-commands/coder/planning/runPlanningSession.ts +14 -3
- package/src/cli/cli-commands/coder/planning/savePlanningChanges.ts +1 -3
- package/src/cli/cli-commands/coder/prepareCoderPackageJsonScripts.ts +304 -0
- package/src/cli/cli-commands/coder/printInitializationSummary.ts +5 -1
- package/src/cli/cli-commands/coder/promptsReadmeTemplate.ts +31 -13
- package/src/cli/cli-commands/coder/run.ts +31 -65
- package/src/cli/cli-commands/coder/server.ts +21 -39
- package/src/cli/cli-commands/coder/verify.ts +3 -0
- package/src/cli/cli-commands/coder.ts +2 -2
- package/src/cli/cli-commands/common/coderCheckCliOptions.ts +107 -0
- package/src/cli/cli-commands/common/projectCliOptions.ts +78 -0
- package/src/cli/cli-commands/common/promptbook-cli/$checkPromptbookCliInstallations.ts +4 -2
- package/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.ts +3 -2
- package/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.ts +8 -4
- package/src/cli/cli-commands/common/promptbook-cli/$updatePromptbookCliInstallation.ts +5 -2
- package/src/cli/cli-commands/common/validateCoderRunOptions.ts +12 -5
- package/src/cli/cli-commands/common/workspaceRepository.ts +7 -19
- package/src/cli/cli-commands/common/workspaceRepositoryCliOptions.ts +2 -0
- package/src/execution/translation/automatic-translate/translateMessages.ts +1 -3
- package/src/other/templates/getTemplatesPipelineCollection.ts +1060 -917
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -1
- package/umd/index.umd.js +1324 -475
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-codex-prompts/checks/CheckBeforeMode.d.ts +20 -0
- package/umd/scripts/run-codex-prompts/checks/checkRepairInstructions.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/checks/createCheckBeforeRepairPrompt.d.ts +9 -0
- package/umd/scripts/run-codex-prompts/checks/limitCheckOutput.d.ts +4 -0
- package/umd/scripts/run-codex-prompts/checks/projectCheck.d.ts +26 -0
- package/umd/scripts/run-codex-prompts/checks/projectScriptReferences.d.ts +7 -0
- package/umd/scripts/run-codex-prompts/checks/runCheckBefore.d.ts +26 -0
- package/umd/scripts/run-codex-prompts/checks/runPromptCheckCommand.d.ts +16 -0
- package/umd/scripts/run-codex-prompts/{testing/runPromptWithTestFeedback.d.ts → checks/runPromptWithCheckFeedback.d.ts} +9 -9
- package/umd/scripts/run-codex-prompts/common/resolveCoderContext.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/common/resolveCoderProjectContext.d.ts +17 -0
- package/umd/scripts/run-codex-prompts/common/resolveInlineOrFileText.d.ts +2 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/quoteBashArgument.d.ts +2 -0
- package/umd/scripts/run-codex-prompts/isolation/mapProjectReferenceToWorktree.d.ts +5 -0
- package/umd/scripts/run-codex-prompts/main/runPromptRound.d.ts +3 -1
- package/umd/scripts/run-codex-prompts/prompts/buildPromptLabel.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/buildPromptLabelForDisplay.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/buildPromptRunTraceContent.d.ts +3 -1
- package/umd/scripts/run-codex-prompts/prompts/formatCoderRunSteps.d.ts +2 -2
- package/umd/scripts/run-codex-prompts/prompts/listUpcomingTasks.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/prompts/printPromptsToBeWritten.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/server/buildCoderServerPromptResponse.d.ts +2 -0
- package/umd/scripts/run-codex-prompts/team/createCoderTeamPromptRunner.d.ts +1 -1
- package/umd/scripts/run-codex-prompts/ui/CoderRunUiState.d.ts +1 -1
- package/umd/src/cli/cli-commands/coder/agentCliOptions.d.ts +5 -0
- package/umd/src/cli/cli-commands/coder/coderAgentRole.d.ts +5 -0
- package/umd/src/cli/cli-commands/coder/coderReferencedArtifacts.d.ts +2 -2
- package/umd/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.d.ts +3 -2
- package/umd/src/cli/cli-commands/coder/ensureCoderPackageJsonFile.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/coder/findLegacyCoderCheckCallers.d.ts +5 -0
- package/umd/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.d.ts +6 -0
- package/umd/src/cli/cli-commands/coder/mergeStringRecordJsonFile.d.ts +5 -3
- package/umd/src/cli/cli-commands/coder/planning/runPlanningSession.d.ts +3 -0
- package/umd/src/cli/cli-commands/coder/prepareCoderPackageJsonScripts.d.ts +12 -0
- package/umd/src/cli/cli-commands/coder.d.ts +1 -1
- package/umd/src/cli/cli-commands/common/coderCheckCliOptions.d.ts +21 -0
- package/umd/src/cli/cli-commands/common/coderCheckCliOptions.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/projectCliOptions.d.ts +30 -0
- package/umd/src/cli/cli-commands/common/projectCliOptions.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/promptbook-cli/$checkPromptbookCliInstallations.d.ts +1 -1
- package/umd/src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.d.ts +1 -1
- package/umd/src/cli/cli-commands/common/promptbook-cli/$resolvePromptbookCliInstallations.d.ts +1 -1
- package/umd/src/cli/cli-commands/common/promptbook-cli/$updatePromptbookCliInstallation.d.ts +1 -1
- package/umd/src/version.d.ts +1 -1
- package/esm/scripts/run-codex-prompts/testing/TestBeforeMode.d.ts +0 -16
- package/esm/scripts/run-codex-prompts/testing/createTestBeforeRepairPrompt.d.ts +0 -9
- package/esm/scripts/run-codex-prompts/testing/limitTestOutput.d.ts +0 -4
- package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +0 -14
- package/esm/scripts/run-codex-prompts/testing/runTestBefore.d.ts +0 -24
- package/umd/scripts/run-codex-prompts/testing/TestBeforeMode.d.ts +0 -16
- package/umd/scripts/run-codex-prompts/testing/createTestBeforeRepairPrompt.d.ts +0 -9
- package/umd/scripts/run-codex-prompts/testing/limitTestOutput.d.ts +0 -4
- package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +0 -14
- package/umd/scripts/run-codex-prompts/testing/runTestBefore.d.ts +0 -24
package/esm/index.es.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import colors from 'colors';
|
|
2
2
|
import commander, { Option } from 'commander';
|
|
3
3
|
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
4
|
-
import {
|
|
5
|
-
import { join, delimiter, relative, basename,
|
|
4
|
+
import { realpath, stat, access, writeFile, readdir, mkdir, readFile, rm, cp, lstat, symlink, rename, unlink, appendFile, copyFile, statfs, constants as constants$1, watch, rmdir, mkdtemp } from 'fs/promises';
|
|
5
|
+
import { resolve, join, delimiter, relative, basename, dirname, isAbsolute, extname } from 'path';
|
|
6
6
|
import { createHash, randomBytes, randomUUID, timingSafeEqual } from 'crypto';
|
|
7
7
|
import { spawn, spawnSync, execFile } from 'child_process';
|
|
8
8
|
import moment from 'moment';
|
|
9
9
|
import * as fs from 'fs';
|
|
10
|
-
import { createWriteStream, mkdirSync, writeFileSync,
|
|
10
|
+
import { constants, createWriteStream, mkdirSync, writeFileSync, statSync, readFileSync, existsSync, realpathSync, lstatSync, linkSync, unlinkSync, renameSync, openSync, fsyncSync, closeSync, promises } from 'fs';
|
|
11
11
|
import * as dotenv from 'dotenv';
|
|
12
12
|
import * as readline from 'readline';
|
|
13
13
|
import { createInterface, emitKeypressEvents, cursorTo, clearLine } from 'readline';
|
|
@@ -51,7 +51,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
51
51
|
* @generated
|
|
52
52
|
* @see https://github.com/webgptorg/promptbook
|
|
53
53
|
*/
|
|
54
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
54
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-49';
|
|
55
55
|
/**
|
|
56
56
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
57
57
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -1746,6 +1746,56 @@ function $reportMissingCliSubcommand(command) {
|
|
|
1746
1746
|
return command.help();
|
|
1747
1747
|
}
|
|
1748
1748
|
|
|
1749
|
+
/**
|
|
1750
|
+
* Registers project selection without capturing a directory during command registration.
|
|
1751
|
+
* @private internal CLI registration helper
|
|
1752
|
+
*/
|
|
1753
|
+
function addProjectPathOption(command) {
|
|
1754
|
+
command.option('--path <directory>', 'Project directory (default: invocation current directory); relative paths start there');
|
|
1755
|
+
}
|
|
1756
|
+
/**
|
|
1757
|
+
* Registers additional context independently of primary-agent selection.
|
|
1758
|
+
* @private internal CLI registration helper
|
|
1759
|
+
*/
|
|
1760
|
+
function addProjectContextOption(command) {
|
|
1761
|
+
command.option('--context <context-or-file>', 'Additional instructions (default: project AGENTS.md); inline text or a project-relative file replaces the default; an empty value disables it');
|
|
1762
|
+
}
|
|
1763
|
+
/**
|
|
1764
|
+
* Captures an invocation's directory at action time. No process-global state is changed.
|
|
1765
|
+
* @private internal CLI normalization helper
|
|
1766
|
+
*/
|
|
1767
|
+
function normalizeProjectCliOptions(options, invocationDirectory = process.cwd()) {
|
|
1768
|
+
const selectedPath = options.path;
|
|
1769
|
+
if (selectedPath !== undefined && !selectedPath.trim()) {
|
|
1770
|
+
throw new EnvironmentMismatchError(spaceTrim('Pass a non-empty project directory in `--path`, or omit it to use the current directory.'));
|
|
1771
|
+
}
|
|
1772
|
+
return { projectDirectory: resolve(invocationDirectory, selectedPath !== null && selectedPath !== void 0 ? selectedPath : '.') };
|
|
1773
|
+
}
|
|
1774
|
+
/**
|
|
1775
|
+
* Validates the selected directory before any setup writes, without selecting an enclosing Git root.
|
|
1776
|
+
* @private shared project resolution for CLI services
|
|
1777
|
+
*/
|
|
1778
|
+
async function resolveProjectDirectory(projectDirectory) {
|
|
1779
|
+
const requestedPath = resolve(projectDirectory);
|
|
1780
|
+
try {
|
|
1781
|
+
const projectPath = await realpath(requestedPath);
|
|
1782
|
+
if (!(await stat(projectPath)).isDirectory()) {
|
|
1783
|
+
throw new EnvironmentMismatchError(spaceTrim(`Project path \`${requestedPath}\` is not a directory.`));
|
|
1784
|
+
}
|
|
1785
|
+
await access(projectPath, constants.R_OK | constants.X_OK);
|
|
1786
|
+
return projectPath;
|
|
1787
|
+
}
|
|
1788
|
+
catch (error) {
|
|
1789
|
+
throw new EnvironmentMismatchError(spaceTrim(`
|
|
1790
|
+
Cannot access project directory \`${requestedPath}\`.
|
|
1791
|
+
Check that it exists, is a directory, and is readable and searchable; correct \`--path\` before retrying.
|
|
1792
|
+
|
|
1793
|
+
${error instanceof Error ? error.message : String(error)}
|
|
1794
|
+
`));
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
// Note: [💞] Shared project registration and resolution helpers.
|
|
1798
|
+
|
|
1749
1799
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1750
1800
|
/**
|
|
1751
1801
|
* All CLI harness names supported by `CliAgent` and `ptbk agent exec`.
|
|
@@ -2105,15 +2155,18 @@ function $initializeAgentChatCommand(program) {
|
|
|
2105
2155
|
command.requiredOption('--agent <agent-book-path>', 'Path to the agent .book file');
|
|
2106
2156
|
addPromptRunnerSelectionOptions(command);
|
|
2107
2157
|
addPromptRunnerRuntimeOptions(command);
|
|
2108
|
-
command
|
|
2158
|
+
addProjectPathOption(command);
|
|
2159
|
+
addProjectContextOption(command);
|
|
2109
2160
|
command.action(handleActionErrors(async (cliOptions, commandProgram) => {
|
|
2161
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
2162
|
+
const projectPath = await resolveProjectDirectory(projectOptions.projectDirectory);
|
|
2110
2163
|
const options = cliOptions;
|
|
2111
2164
|
const runnerOptions = normalizeAgentCommandRunnerOptions(options, commandProgram);
|
|
2112
2165
|
const { runAgentChat } = await Promise.resolve().then(function () { return runAgentChat$1; });
|
|
2113
2166
|
await runAgentChat({
|
|
2114
2167
|
agentPath: resolveRequiredAgentPath(options),
|
|
2115
2168
|
context: options.context,
|
|
2116
|
-
currentWorkingDirectory:
|
|
2169
|
+
currentWorkingDirectory: projectPath,
|
|
2117
2170
|
...runnerOptions,
|
|
2118
2171
|
});
|
|
2119
2172
|
}));
|
|
@@ -2139,8 +2192,11 @@ function $initializeAgentExecCommand(program) {
|
|
|
2139
2192
|
command.requiredOption('--message <message>', 'User message to send to the agent');
|
|
2140
2193
|
addPromptRunnerSelectionOptions(command);
|
|
2141
2194
|
addPromptRunnerRuntimeOptions(command);
|
|
2142
|
-
command
|
|
2195
|
+
addProjectPathOption(command);
|
|
2196
|
+
addProjectContextOption(command);
|
|
2143
2197
|
command.action(handleActionErrors(async (cliOptions, commandProgram) => {
|
|
2198
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
2199
|
+
const projectPath = await resolveProjectDirectory(projectOptions.projectDirectory);
|
|
2144
2200
|
const options = cliOptions;
|
|
2145
2201
|
const runnerOptions = normalizeAgentCommandRunnerOptions(options, commandProgram);
|
|
2146
2202
|
const { runAgentExec } = await Promise.resolve().then(function () { return runAgentExec$1; });
|
|
@@ -2148,7 +2204,7 @@ function $initializeAgentExecCommand(program) {
|
|
|
2148
2204
|
agentPath: resolveRequiredAgentPath(options),
|
|
2149
2205
|
context: options.context,
|
|
2150
2206
|
message: resolveRequiredAgentMessage(options),
|
|
2151
|
-
currentWorkingDirectory:
|
|
2207
|
+
currentWorkingDirectory: projectPath,
|
|
2152
2208
|
...runnerOptions,
|
|
2153
2209
|
});
|
|
2154
2210
|
}));
|
|
@@ -2452,8 +2508,11 @@ function $initializeAgentInitCommand(program) {
|
|
|
2452
2508
|
- ${AGENT_BOOK_FILE_PATH}
|
|
2453
2509
|
- ${AGENT_BOOK_LANGUAGE_MANUAL_FILE_PATH.replace(/\\/gu, '/')}
|
|
2454
2510
|
`));
|
|
2455
|
-
command
|
|
2456
|
-
|
|
2511
|
+
addProjectPathOption(command);
|
|
2512
|
+
command.action(handleActionErrors(async (cliOptions) => {
|
|
2513
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
2514
|
+
const projectPath = await resolveProjectDirectory(projectOptions.projectDirectory);
|
|
2515
|
+
const summary = await initializeAgentProjectConfiguration(projectPath);
|
|
2457
2516
|
printAgentInitializationSummary(summary);
|
|
2458
2517
|
}));
|
|
2459
2518
|
}
|
|
@@ -2508,15 +2567,21 @@ function $initializeAgentRunnerCommand(program, options) {
|
|
|
2508
2567
|
`));
|
|
2509
2568
|
addPromptRunnerSelectionOptions(command);
|
|
2510
2569
|
addPromptRunnerExecutionOptions(command);
|
|
2570
|
+
addProjectPathOption(command);
|
|
2511
2571
|
(_a = options.configureCommand) === null || _a === void 0 ? void 0 : _a.call(options, command);
|
|
2512
2572
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
2513
|
-
const
|
|
2573
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
2574
|
+
const projectPath = await resolveProjectDirectory(projectOptions.projectDirectory);
|
|
2575
|
+
const runOptions = {
|
|
2576
|
+
...createAgentRunOptionsFromCliOptions(cliOptions),
|
|
2577
|
+
projectPath,
|
|
2578
|
+
};
|
|
2514
2579
|
const execute = await options.loadExecutor();
|
|
2515
2580
|
if (options.executionMode === 'watch') {
|
|
2516
2581
|
const { runPersistentAgentWatch } = await Promise.resolve().then(function () { return runPersistentAgentWatch$1; });
|
|
2517
2582
|
await runPersistentAgentWatch({
|
|
2518
2583
|
commandDisplayName: `ptbk agent-folder ${options.commandName}`,
|
|
2519
|
-
logDirectoryPath:
|
|
2584
|
+
logDirectoryPath: projectPath,
|
|
2520
2585
|
runWatch: async () => {
|
|
2521
2586
|
await execute(runOptions);
|
|
2522
2587
|
},
|
|
@@ -24750,7 +24815,7 @@ async function appendScriptExecutionLogFinish({ scriptPath, logPath, status, det
|
|
|
24750
24815
|
* Distinguishes prompt-runner and verification temp shells in the shared runtime log.
|
|
24751
24816
|
*/
|
|
24752
24817
|
function describeTempScriptKind(scriptPath) {
|
|
24753
|
-
return scriptPath.toLowerCase().endsWith('.
|
|
24818
|
+
return scriptPath.toLowerCase().endsWith('.check.sh') ? 'check shell' : 'runner shell';
|
|
24754
24819
|
}
|
|
24755
24820
|
|
|
24756
24821
|
/**
|
|
@@ -24953,28 +25018,44 @@ async function runBashScriptWithOutput(options) {
|
|
|
24953
25018
|
/**
|
|
24954
25019
|
* Handles process exit and resolves or rejects accordingly.
|
|
24955
25020
|
*/
|
|
24956
|
-
const handleExit = (code) => {
|
|
25021
|
+
const handleExit = (code, signal) => {
|
|
24957
25022
|
var _a;
|
|
24958
25023
|
if ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
24959
25024
|
settleWithLog('cancelled', () => reject(options.signal.reason), options.signal.reason);
|
|
24960
25025
|
return;
|
|
24961
25026
|
}
|
|
24962
|
-
if (code === 0) {
|
|
24963
|
-
settleWithLog('succeeded', () =>
|
|
25027
|
+
if (code === 0 && !signal) {
|
|
25028
|
+
settleWithLog('succeeded', () => {
|
|
25029
|
+
var _a;
|
|
25030
|
+
// Cancellation can arrive while the runtime log footer is being flushed.
|
|
25031
|
+
if ((_a = options.signal) === null || _a === void 0 ? void 0 : _a.aborted)
|
|
25032
|
+
reject(options.signal.reason);
|
|
25033
|
+
else
|
|
25034
|
+
resolve(spaceTrim$1(output));
|
|
25035
|
+
});
|
|
24964
25036
|
return;
|
|
24965
25037
|
}
|
|
24966
|
-
const failure = new
|
|
24967
|
-
|
|
25038
|
+
const failure = new NotAllowed(spaceTrim$1((block) => `
|
|
25039
|
+
Command "bash ${scriptPathPosix}" exited with code ${code !== null && code !== void 0 ? code : 'unknown'}${signal ? ` and signal ${signal}` : ''}.
|
|
25040
|
+
${block(output)}
|
|
25041
|
+
`));
|
|
25042
|
+
settleWithLog(`failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}${signal ? ` and signal ${signal}` : ''}`, () => reject(failure), failure);
|
|
24968
25043
|
};
|
|
24969
25044
|
// Wait for `close`, not only `exit`, because the Bash wrapper can still be flushing its tee process
|
|
24970
25045
|
// substitutions after the direct shell exits.
|
|
24971
25046
|
commandProcess.on('close', handleExit);
|
|
24972
25047
|
commandProcess.on('disconnect', () => {
|
|
24973
|
-
const failure = new
|
|
25048
|
+
const failure = new NotAllowed(spaceTrim$1((block) => `
|
|
25049
|
+
Command "bash ${scriptPathPosix}" disconnected.
|
|
25050
|
+
${block(output)}
|
|
25051
|
+
`));
|
|
24974
25052
|
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
24975
25053
|
});
|
|
24976
25054
|
commandProcess.on('error', (error) => {
|
|
24977
|
-
const failure = new
|
|
25055
|
+
const failure = new NotAllowed(spaceTrim$1((block) => `
|
|
25056
|
+
Command "bash ${scriptPathPosix}" failed: ${error.message}
|
|
25057
|
+
${block(output)}
|
|
25058
|
+
`));
|
|
24978
25059
|
settleWithLog('failed before completion', () => reject(failure), failure);
|
|
24979
25060
|
});
|
|
24980
25061
|
/** Reuses the process-tree terminator; settlement waits for stream closure and the trace footer. */
|
|
@@ -26430,6 +26511,11 @@ class GeminiRunner {
|
|
|
26430
26511
|
}
|
|
26431
26512
|
}
|
|
26432
26513
|
|
|
26514
|
+
/** Quotes one literal argument, including spaces and shell metacharacters, for a generated Bash script. */
|
|
26515
|
+
function quoteBashArgument(value) {
|
|
26516
|
+
return `'${value.replace(/'/gu, "'\\''")}'`;
|
|
26517
|
+
}
|
|
26518
|
+
|
|
26433
26519
|
/**
|
|
26434
26520
|
* Builds the shell script that runs GitHub Copilot CLI with the prompt and coding context.
|
|
26435
26521
|
*/
|
|
@@ -26439,7 +26525,7 @@ function buildGitHubCopilotScript(options) {
|
|
|
26439
26525
|
const modelArgument = options.model ? ` --model ${options.model}` : '';
|
|
26440
26526
|
const thinkingLevelArgument = options.thinkingLevel ? ` --reasoning-effort ${options.thinkingLevel}` : '';
|
|
26441
26527
|
return spaceTrim((block) => `
|
|
26442
|
-
cd
|
|
26528
|
+
cd ${quoteBashArgument(projectPath)}
|
|
26443
26529
|
|
|
26444
26530
|
if [ -f .env ]; then
|
|
26445
26531
|
set -a
|
|
@@ -26880,7 +26966,7 @@ function buildCodexScript(options) {
|
|
|
26880
26966
|
...(options.isMachineReadableProgressEnabled ? [' --json \\'] : []),
|
|
26881
26967
|
' --local-provider none \\',
|
|
26882
26968
|
` --sandbox ${options.sandbox} \\`,
|
|
26883
|
-
` -C ${projectPath} \\`,
|
|
26969
|
+
` -C ${quoteBashArgument(projectPath)} \\`,
|
|
26884
26970
|
' --skip-git-repo-check \\',
|
|
26885
26971
|
` <<'${delimiter}'`,
|
|
26886
26972
|
'',
|
|
@@ -29216,7 +29302,7 @@ function buildSessionRows(options, bodyWidth, pausePresentation) {
|
|
|
29216
29302
|
...buildOptionalSessionRow('Server', options.config.serverUrl
|
|
29217
29303
|
? buildTerminalUrlLink(options.config.serverUrl, bodyWidth - SESSION_LABEL_WIDTH - 1)
|
|
29218
29304
|
: undefined),
|
|
29219
|
-
...buildOptionalSessionRow('
|
|
29305
|
+
...buildOptionalSessionRow('Check', options.config.checkCommand),
|
|
29220
29306
|
];
|
|
29221
29307
|
return [
|
|
29222
29308
|
{
|
|
@@ -31710,7 +31796,7 @@ function createCoderRunOptionsForAgent(options) {
|
|
|
31710
31796
|
return {
|
|
31711
31797
|
dryRun: false,
|
|
31712
31798
|
context: undefined,
|
|
31713
|
-
|
|
31799
|
+
checkCommand: undefined,
|
|
31714
31800
|
preserveLogs: false,
|
|
31715
31801
|
noUi: options.noUi,
|
|
31716
31802
|
thinkingLevel: options.thinkingLevel,
|
|
@@ -32812,40 +32898,207 @@ function createCoderRunStepTracker(onStepStarted) {
|
|
|
32812
32898
|
}
|
|
32813
32899
|
|
|
32814
32900
|
/**
|
|
32815
|
-
* Maximum amount of
|
|
32901
|
+
* Maximum amount of check output embedded into an agent prompt.
|
|
32902
|
+
*/
|
|
32903
|
+
const MAX_CHECK_OUTPUT_CHARS = 12000;
|
|
32904
|
+
/**
|
|
32905
|
+
* Limits check output while keeping the end of the output, where check tools usually print the failure summary.
|
|
32906
|
+
*/
|
|
32907
|
+
function limitCheckOutput(checkOutput) {
|
|
32908
|
+
const normalizedCheckOutput = checkOutput.trim();
|
|
32909
|
+
if (normalizedCheckOutput.length <= MAX_CHECK_OUTPUT_CHARS) {
|
|
32910
|
+
return normalizedCheckOutput;
|
|
32911
|
+
}
|
|
32912
|
+
return `[..., check output truncated to the last ${MAX_CHECK_OUTPUT_CHARS} characters...]\n${normalizedCheckOutput.slice(-MAX_CHECK_OUTPUT_CHARS)}`;
|
|
32913
|
+
}
|
|
32914
|
+
|
|
32915
|
+
/**
|
|
32916
|
+
* Modes supported by `ptbk coder run --check-before`.
|
|
32917
|
+
*/
|
|
32918
|
+
const CHECK_BEFORE_MODE_VALUES = ['no', 'yes-and-fail', 'yes-and-fix'];
|
|
32919
|
+
/**
|
|
32920
|
+
* Default check command used when a pre-coding mode is enabled without an explicit `--check` command.
|
|
32921
|
+
*/
|
|
32922
|
+
const DEFAULT_CODER_CHECK_COMMAND = 'npm run check';
|
|
32923
|
+
/**
|
|
32924
|
+
* Resolves the shared command without enabling checks when both command and preflight mode are absent.
|
|
32925
|
+
*/
|
|
32926
|
+
function resolveCoderCheckCommand(checkCommand, checkBefore = 'no') {
|
|
32927
|
+
return checkCommand !== null && checkCommand !== void 0 ? checkCommand : (checkBefore === 'no' ? undefined : DEFAULT_CODER_CHECK_COMMAND);
|
|
32928
|
+
}
|
|
32929
|
+
/**
|
|
32930
|
+
* Checks whether a value is a supported `--check-before` mode.
|
|
32931
|
+
*/
|
|
32932
|
+
function isCheckBeforeMode(value) {
|
|
32933
|
+
return CHECK_BEFORE_MODE_VALUES.includes(value);
|
|
32934
|
+
}
|
|
32935
|
+
|
|
32936
|
+
/** Conventional root command boundaries, including subshells and environment assignments. */
|
|
32937
|
+
const SCRIPT_COMMAND_PREFIX = String.raw `(?:^|&&|\|\||;|\n|[()])\s*(?:(?:env\s+)?[A-Za-z_]\w*=(?:[^\s'";&|()]+|"[^"]*"|'[^']*')\s+)*`;
|
|
32938
|
+
/** Package-manager options which do not select a different directory or workspace. */
|
|
32939
|
+
const QUIET_OPTIONS = String.raw `(?:(?:--silent|--quiet|-s|-q)\s+)*`;
|
|
32940
|
+
/** Quoted script names preserve spaces, while unquoted names use conventional npm identifier characters. */
|
|
32941
|
+
const SCRIPT_NAME = String.raw `(?:(["'])([^"'\r\n]+)\1|([\w:.-]+))(?=\s|$|[;&|()])`;
|
|
32942
|
+
/** Quoted payloads and escaped characters are opaque to this configuration inspection. */
|
|
32943
|
+
const OPAQUE_ARGUMENT = String.raw `"(?:\\.|[^"\\])*"|'[^']*'|\\[\s\S]`;
|
|
32944
|
+
/** Only references before a conventional directory change can confidently belong to the root package. */
|
|
32945
|
+
const DIRECTORY_CHANGE_COMMAND = new RegExp(`${SCRIPT_COMMAND_PREFIX}(?:cd|pushd|popd)(?=\\s|$)|(?<argument>${OPAQUE_ARGUMENT})`, 'gu');
|
|
32946
|
+
/** Arguments up to the next conventional command boundary, preserving quoted payloads as opaque text. */
|
|
32947
|
+
const SCRIPT_ARGUMENTS = new RegExp(String.raw `^(?:${OPAQUE_ARGUMENT}|[^;&|\n()'"\\])*`, 'u');
|
|
32948
|
+
/** Package-manager options that select validation from a different directory or workspace. */
|
|
32949
|
+
const PROJECT_OVERRIDE_OPTION = /\s(?:--prefix|--dir|--cwd|-C|--workspace|--workspaces|-w|--filter)(?:\s|=|$)/u;
|
|
32950
|
+
/**
|
|
32951
|
+
* Reads conventional npm/pnpm/yarn script references for configuration inspection.
|
|
32952
|
+
* Commands are still executed verbatim by the existing shell runner; this helper neither parses nor rewrites shells.
|
|
32953
|
+
* Options selecting other workspaces remain opaque so their scripts are not mistaken for root validation.
|
|
32954
|
+
* Inspection stops at the first directory change; quoted examples do not change the inspected workspace.
|
|
32816
32955
|
*/
|
|
32817
|
-
|
|
32956
|
+
function projectScriptReferences(command) {
|
|
32957
|
+
var _a;
|
|
32958
|
+
const directoryChange = [...command.matchAll(DIRECTORY_CHANGE_COMMAND)].find((match) => { var _a; return ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.argument) === undefined; });
|
|
32959
|
+
if (directoryChange)
|
|
32960
|
+
command = command.slice(0, directoryChange.index);
|
|
32961
|
+
const references = [
|
|
32962
|
+
...command.matchAll(new RegExp(`${SCRIPT_COMMAND_PREFIX}(?:npm|pnpm|yarn)\\s+${QUIET_OPTIONS}(?:run(?:-script)?\\s+${QUIET_OPTIONS}${SCRIPT_NAME}|(?:test|t)(?=\\s|$|[;&|()]))` +
|
|
32963
|
+
`|(?<argument>${OPAQUE_ARGUMENT})`, 'gu')),
|
|
32964
|
+
]
|
|
32965
|
+
.filter((match) => isRootProjectScriptReference(command, match))
|
|
32966
|
+
.map((match) => { var _a, _b; return (_b = (_a = match[2]) !== null && _a !== void 0 ? _a : match[3]) !== null && _b !== void 0 ? _b : 'test'; });
|
|
32967
|
+
for (const match of command.matchAll(new RegExp(`${SCRIPT_COMMAND_PREFIX}(?:pnpm|yarn)\\s+${QUIET_OPTIONS}(?!run\\b|-)${SCRIPT_NAME}` +
|
|
32968
|
+
`|(?<argument>${OPAQUE_ARGUMENT})`, 'gu')))
|
|
32969
|
+
if (isRootProjectScriptReference(command, match))
|
|
32970
|
+
references.push(((_a = match[2]) !== null && _a !== void 0 ? _a : match[3]));
|
|
32971
|
+
return [...new Set(references)];
|
|
32972
|
+
}
|
|
32973
|
+
/** Excludes quoted examples and package-manager directory overrides without altering the executed command. */
|
|
32974
|
+
function isRootProjectScriptReference(command, match) {
|
|
32975
|
+
var _a, _b, _c, _d;
|
|
32976
|
+
if (((_a = match.groups) === null || _a === void 0 ? void 0 : _a.argument) !== undefined)
|
|
32977
|
+
return false;
|
|
32978
|
+
const argumentsText = (_c = (_b = command.slice(match.index + match[0].length).match(SCRIPT_ARGUMENTS)) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : '';
|
|
32979
|
+
// Flags after npm's `--` separator belong to the leaf tool, rather than the package manager.
|
|
32980
|
+
const packageManagerArguments = (_d = argumentsText.split(/\s--(?:\s|$)/u)[0]) !== null && _d !== void 0 ? _d : '';
|
|
32981
|
+
return !PROJECT_OVERRIDE_OPTION.test(packageManagerArguments);
|
|
32982
|
+
}
|
|
32983
|
+
|
|
32818
32984
|
/**
|
|
32819
|
-
*
|
|
32985
|
+
* Failing setup placeholder used only when initialization finds no usable project validation scripts.
|
|
32820
32986
|
*/
|
|
32821
|
-
|
|
32822
|
-
|
|
32823
|
-
|
|
32824
|
-
|
|
32987
|
+
const CHECK_SETUP_PLACEHOLDER_COMMAND = `node -e "console.error('Configure package.json scripts.check with project validation commands before running Coder.'); process.exit(1)"`;
|
|
32988
|
+
/** Retired generated script names inspected only to report stale caller configuration. */
|
|
32989
|
+
const LEGACY_CHECK_SCRIPT_NAMES$1 = new Set(['test-for-ptbk-coder', 'check-for-ptbk-coder']);
|
|
32990
|
+
/**
|
|
32991
|
+
* A missing or unconfigured project check needs project-owner setup, rather than model repair retries.
|
|
32992
|
+
*/
|
|
32993
|
+
class CoderCheckSetupError extends NotAllowed {
|
|
32994
|
+
/** Creates an actionable project check setup error. */
|
|
32995
|
+
constructor(details) {
|
|
32996
|
+
super(spaceTrim$1(`
|
|
32997
|
+
Project check is not configured: ${details}
|
|
32998
|
+
|
|
32999
|
+
Configure the selected validation scripts in \`package.json\`. The canonical aggregate is \`scripts.check\`, invoked as \`${DEFAULT_CODER_CHECK_COMMAND}\`.
|
|
33000
|
+
Coder will not replace missing validation with a successful placeholder or tests alone.
|
|
33001
|
+
`));
|
|
33002
|
+
Object.setPrototypeOf(this, CoderCheckSetupError.prototype);
|
|
32825
33003
|
}
|
|
32826
|
-
return `[..., test output truncated to the last ${MAX_TEST_OUTPUT_CHARS} characters...]\n${normalizedTestOutput.slice(-MAX_TEST_OUTPUT_CHARS)}`;
|
|
32827
33004
|
}
|
|
33005
|
+
/**
|
|
33006
|
+
* Detects the generated setup placeholder and the conventional npm unconfigured-test placeholder.
|
|
33007
|
+
*/
|
|
33008
|
+
function isCheckSetupRequired(command) {
|
|
33009
|
+
return (!command.trim() ||
|
|
33010
|
+
command.includes('Configure package.json scripts.check') ||
|
|
33011
|
+
/no test specified/iu.test(command));
|
|
33012
|
+
}
|
|
33013
|
+
/**
|
|
33014
|
+
* Inspects root project check references before an initial check or repair loop can start.
|
|
33015
|
+
* Flags and shell composition do not bypass setup validation; execution still uses the existing shell runner.
|
|
33016
|
+
*/
|
|
33017
|
+
async function assertProjectCheckIsConfigured(command, projectPath) {
|
|
33018
|
+
var _a, _b;
|
|
33019
|
+
if (!command)
|
|
33020
|
+
return;
|
|
33021
|
+
const references = projectScriptReferences(command);
|
|
33022
|
+
if (references.length === 0)
|
|
33023
|
+
return;
|
|
33024
|
+
let packageJson;
|
|
33025
|
+
try {
|
|
33026
|
+
packageJson = JSON.parse(await readFile(join(projectPath, 'package.json'), 'utf-8'));
|
|
33027
|
+
}
|
|
33028
|
+
catch (error) {
|
|
33029
|
+
throw new CoderCheckSetupError(`cannot read package.json (${error instanceof Error ? error.message : String(error)}).`);
|
|
33030
|
+
}
|
|
33031
|
+
for (const reference of references) {
|
|
33032
|
+
if (LEGACY_CHECK_SCRIPT_NAMES$1.has(reference) && ((_a = packageJson === null || packageJson === void 0 ? void 0 : packageJson.scripts) === null || _a === void 0 ? void 0 : _a[reference]) === undefined) {
|
|
33033
|
+
throw new CoderCheckSetupError(`scripts.${reference} is missing and is no longer initialized by Coder. Update this caller to \`--check "${DEFAULT_CODER_CHECK_COMMAND}"\`; no compatibility alias is generated.`);
|
|
33034
|
+
}
|
|
33035
|
+
assertProjectCheckScriptsAreConfigured((_b = packageJson === null || packageJson === void 0 ? void 0 : packageJson.scripts) !== null && _b !== void 0 ? _b : {}, reference);
|
|
33036
|
+
}
|
|
33037
|
+
}
|
|
33038
|
+
/**
|
|
33039
|
+
* Validates the project-owned check definition without running commands or changing its scope.
|
|
33040
|
+
* Initialization and execution use this same setup diagnostic for missing leaves and recursive callers.
|
|
33041
|
+
*/
|
|
33042
|
+
function assertProjectCheckScriptsAreConfigured(scripts, name = 'check') {
|
|
33043
|
+
assertReferencedScriptsAreConfigured(name, scripts, new Set());
|
|
33044
|
+
}
|
|
33045
|
+
/** Detects missing/placeholder leaf validation and recursive npm callers before a model repair loop can start. */
|
|
33046
|
+
function assertReferencedScriptsAreConfigured(name, scripts, ancestors) {
|
|
33047
|
+
if (ancestors.has(name))
|
|
33048
|
+
throw new CoderCheckSetupError(`scripts.${name} recursively calls the check pipeline.`);
|
|
33049
|
+
const command = scripts[name];
|
|
33050
|
+
if (typeof command !== 'string' || isCheckSetupRequired(command)) {
|
|
33051
|
+
throw new CoderCheckSetupError(`scripts.${name} is missing, empty, or contains a setup placeholder.`);
|
|
33052
|
+
}
|
|
33053
|
+
if (/^coder:(?:run|fix)$/u.test(name) || /\b(?:ptbk|promptbook)\s+coder\s+(?:run|fix)\b/u.test(command)) {
|
|
33054
|
+
throw new CoderCheckSetupError(`scripts.${name} calls Coder execution instead of project validation.`);
|
|
33055
|
+
}
|
|
33056
|
+
const nextAncestors = new Set([...ancestors, name]);
|
|
33057
|
+
// The shared inspector keeps root references before a directory change and leaves child workspaces opaque.
|
|
33058
|
+
for (const reference of projectScriptReferences(command)) {
|
|
33059
|
+
assertReferencedScriptsAreConfigured(reference, scripts, nextAncestors);
|
|
33060
|
+
}
|
|
33061
|
+
for (const prefix of ['pre', 'post']) {
|
|
33062
|
+
const lifecycleName = `${prefix}${name}`;
|
|
33063
|
+
if (scripts[lifecycleName] !== undefined)
|
|
33064
|
+
assertReferencedScriptsAreConfigured(lifecycleName, scripts, nextAncestors);
|
|
33065
|
+
}
|
|
33066
|
+
}
|
|
33067
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
32828
33068
|
|
|
32829
33069
|
/**
|
|
32830
|
-
* Runs the configured
|
|
33070
|
+
* Runs the configured check command inside the project root and returns its output.
|
|
32831
33071
|
*/
|
|
32832
|
-
async function
|
|
33072
|
+
async function runPromptCheckCommand(options) {
|
|
33073
|
+
await assertProjectCheckIsConfigured(options.command, options.projectPath);
|
|
32833
33074
|
const projectPath = toPosixPath(options.projectPath);
|
|
32834
33075
|
return await $runGoScriptWithOutput({
|
|
32835
33076
|
scriptPath: options.scriptPath,
|
|
33077
|
+
projectPath: options.projectPath,
|
|
32836
33078
|
scriptContent: spaceTrim(`
|
|
32837
|
-
cd
|
|
33079
|
+
cd ${quoteBashArgument(projectPath)} || exit 1
|
|
32838
33080
|
${options.command}
|
|
32839
33081
|
`),
|
|
32840
33082
|
logPath: options.logPath,
|
|
32841
33083
|
preserveArtifactsOnSuccess: options.preserveArtifactsOnSuccess,
|
|
33084
|
+
signal: options.signal,
|
|
32842
33085
|
});
|
|
32843
33086
|
}
|
|
32844
33087
|
|
|
32845
33088
|
/**
|
|
32846
|
-
*
|
|
33089
|
+
* Shared constraints for initial repair PRDs and post-prompt check feedback.
|
|
33090
|
+
*/
|
|
33091
|
+
const CHECK_REPAIR_INSTRUCTIONS = spaceTrim$1(`
|
|
33092
|
+
Fix the underlying lint, typechecking, build, generated-code consistency, or test failure without weakening validation.
|
|
33093
|
+
Do not delete assertions, disable lint rules, remove failing checks from the aggregate, lower quality thresholds,
|
|
33094
|
+
skip a build, or force exit code zero merely to obtain a pass. Keep the project's chosen check scope intact.
|
|
33095
|
+
Missing or unconfigured validation requires project-owner setup; never replace it with a meaningless green result.
|
|
33096
|
+
`);
|
|
33097
|
+
|
|
33098
|
+
/**
|
|
33099
|
+
* Maximum number of coding attempts allowed for the same prompt when check keeps failing.
|
|
32847
33100
|
*/
|
|
32848
|
-
const
|
|
33101
|
+
const MAX_PROMPT_CHECK_ATTEMPTS = 3;
|
|
32849
33102
|
/**
|
|
32850
33103
|
* File extension used by generated shell scripts.
|
|
32851
33104
|
*/
|
|
@@ -32853,12 +33106,18 @@ const SHELL_SCRIPT_EXTENSION = '.sh';
|
|
|
32853
33106
|
/**
|
|
32854
33107
|
* Runs one coding prompt and, when configured, verifies it with a shell command that can feed failures back.
|
|
32855
33108
|
*/
|
|
32856
|
-
async function
|
|
32857
|
-
var _a, _b, _c, _d;
|
|
32858
|
-
|
|
33109
|
+
async function runPromptWithCheckFeedback(options) {
|
|
33110
|
+
var _a, _b, _c, _d, _e;
|
|
33111
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
33112
|
+
const normalizedCheckCommand = (_b = options.checkCommand) === null || _b === void 0 ? void 0 : _b.trim();
|
|
33113
|
+
// Injected executors own their setup validation, just as they own command execution. The shared real executor
|
|
33114
|
+
// validates again after each agent attempt in case it changed the project's validation configuration.
|
|
33115
|
+
if (!options.runPromptCheckCommandExecutor) {
|
|
33116
|
+
await assertProjectCheckIsConfigured(normalizedCheckCommand, options.projectPath);
|
|
33117
|
+
}
|
|
32859
33118
|
const stepTracker = createCoderRunStepTracker(options.onStepStarted);
|
|
32860
|
-
if (!
|
|
32861
|
-
(
|
|
33119
|
+
if (!normalizedCheckCommand) {
|
|
33120
|
+
(_c = options.onAttemptStarted) === null || _c === void 0 ? void 0 : _c.call(options, 1);
|
|
32862
33121
|
await waitForPromptAttemptPauseCheckpoint(options.waitForPauseCheckpoint, options.runner.name, 1);
|
|
32863
33122
|
const result = await runRunnerPromptStep({
|
|
32864
33123
|
runOptions: options,
|
|
@@ -32868,10 +33127,10 @@ async function runPromptWithTestFeedback(options) {
|
|
|
32868
33127
|
});
|
|
32869
33128
|
return { ...result, attemptCount: 1, steps: stepTracker.steps };
|
|
32870
33129
|
}
|
|
32871
|
-
const
|
|
33130
|
+
const runPromptCheckCommandExecutor = (_d = options.runPromptCheckCommandExecutor) !== null && _d !== void 0 ? _d : runPromptCheckCommand;
|
|
32872
33131
|
let promptForCurrentAttempt = options.prompt;
|
|
32873
|
-
for (let attemptCount = 1; attemptCount <=
|
|
32874
|
-
(
|
|
33132
|
+
for (let attemptCount = 1; attemptCount <= MAX_PROMPT_CHECK_ATTEMPTS; attemptCount++) {
|
|
33133
|
+
(_e = options.onAttemptStarted) === null || _e === void 0 ? void 0 : _e.call(options, attemptCount);
|
|
32875
33134
|
await waitForPromptAttemptPauseCheckpoint(options.waitForPauseCheckpoint, options.runner.name, attemptCount);
|
|
32876
33135
|
const result = await runRunnerPromptStep({
|
|
32877
33136
|
runOptions: options,
|
|
@@ -32879,42 +33138,44 @@ async function runPromptWithTestFeedback(options) {
|
|
|
32879
33138
|
kind: attemptCount === 1 ? 'implementation' : 'fixing',
|
|
32880
33139
|
stepTracker,
|
|
32881
33140
|
});
|
|
32882
|
-
await
|
|
32883
|
-
console.info(colors.gray(`Running
|
|
32884
|
-
const
|
|
32885
|
-
|
|
32886
|
-
|
|
33141
|
+
await waitForCheckPauseCheckpoint(options.waitForPauseCheckpoint, normalizedCheckCommand, attemptCount);
|
|
33142
|
+
console.info(colors.gray(`Running check command after attempt #${attemptCount}: ${normalizedCheckCommand}`));
|
|
33143
|
+
const failedCheck = await runCheckStep({
|
|
33144
|
+
runPromptCheckCommandExecutor,
|
|
33145
|
+
checkCommand: normalizedCheckCommand,
|
|
32887
33146
|
runOptions: options,
|
|
32888
33147
|
stepTracker,
|
|
32889
33148
|
});
|
|
32890
|
-
if (
|
|
33149
|
+
if (failedCheck === undefined) {
|
|
32891
33150
|
return { ...result, attemptCount, steps: stepTracker.steps };
|
|
32892
33151
|
}
|
|
32893
|
-
const
|
|
32894
|
-
const
|
|
32895
|
-
if (attemptCount >=
|
|
32896
|
-
console.error(colors.red(`
|
|
32897
|
-
throw new
|
|
33152
|
+
const fullCheckOutput = formatUnknownErrorDetails(failedCheck.error);
|
|
33153
|
+
const feedbackCheckOutput = limitCheckOutput(fullCheckOutput);
|
|
33154
|
+
if (attemptCount >= MAX_PROMPT_CHECK_ATTEMPTS) {
|
|
33155
|
+
console.error(colors.red(`Check failed for ${options.promptLabel} after ${attemptCount} attempts.`));
|
|
33156
|
+
throw new NotAllowed(buildFinalCheckFailureMessage({
|
|
32898
33157
|
promptLabel: options.promptLabel,
|
|
32899
|
-
|
|
33158
|
+
checkCommand: normalizedCheckCommand,
|
|
32900
33159
|
attemptCount,
|
|
32901
|
-
|
|
33160
|
+
checkOutput: fullCheckOutput,
|
|
32902
33161
|
}));
|
|
32903
33162
|
}
|
|
32904
|
-
console.warn(colors.yellow(`
|
|
32905
|
-
promptForCurrentAttempt = appendCoderContext(options.prompt,
|
|
32906
|
-
|
|
33163
|
+
console.warn(colors.yellow(`Check failed for ${options.promptLabel} on attempt #${attemptCount}. Sending feedback to ${options.runner.name} and retrying...`));
|
|
33164
|
+
promptForCurrentAttempt = appendCoderContext(options.prompt, buildCheckFeedback({
|
|
33165
|
+
checkCommand: normalizedCheckCommand,
|
|
32907
33166
|
failedAttemptCount: attemptCount,
|
|
32908
|
-
|
|
33167
|
+
checkOutput: feedbackCheckOutput,
|
|
32909
33168
|
}));
|
|
32910
33169
|
}
|
|
32911
|
-
throw new
|
|
33170
|
+
throw new UnexpectedError('Unexpected prompt check state.');
|
|
32912
33171
|
}
|
|
32913
33172
|
/**
|
|
32914
33173
|
* Runs one coding attempt through the runner, timing it and recording it as an implementation or fixing step.
|
|
32915
33174
|
*/
|
|
32916
33175
|
async function runRunnerPromptStep(options) {
|
|
33176
|
+
var _a, _b;
|
|
32917
33177
|
const { runOptions, prompt, kind, stepTracker } = options;
|
|
33178
|
+
(_a = runOptions.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
32918
33179
|
await stepTracker.startStep(kind);
|
|
32919
33180
|
const stepStartedTimeMs = Date.now();
|
|
32920
33181
|
const result = await runOptions.runner.runPrompt({
|
|
@@ -32924,33 +33185,41 @@ async function runRunnerPromptStep(options) {
|
|
|
32924
33185
|
logPath: runOptions.logPath,
|
|
32925
33186
|
preserveArtifactsOnSuccess: runOptions.preserveArtifactsOnSuccess,
|
|
32926
33187
|
waitForPauseCheckpoint: runOptions.waitForPauseCheckpoint,
|
|
33188
|
+
...(runOptions.signal ? { signal: runOptions.signal } : {}),
|
|
32927
33189
|
});
|
|
33190
|
+
(_b = runOptions.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
|
|
32928
33191
|
stepTracker.finishStep({ kind, usage: result.usage, durationMs: Date.now() - stepStartedTimeMs }, result.loginMethod);
|
|
32929
33192
|
return result;
|
|
32930
33193
|
}
|
|
32931
33194
|
/**
|
|
32932
|
-
* Runs the
|
|
32933
|
-
* returns the failure (or `undefined` when the
|
|
33195
|
+
* Runs the check command, timing it and recording it as a checking step regardless of the outcome, and
|
|
33196
|
+
* returns the failure (or `undefined` when the check passed).
|
|
32934
33197
|
*/
|
|
32935
|
-
async function
|
|
32936
|
-
|
|
32937
|
-
|
|
33198
|
+
async function runCheckStep(options) {
|
|
33199
|
+
var _a, _b, _c;
|
|
33200
|
+
const { runPromptCheckCommandExecutor, checkCommand, runOptions, stepTracker } = options;
|
|
33201
|
+
(_a = runOptions.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
33202
|
+
await stepTracker.startStep('checking');
|
|
32938
33203
|
const stepStartedTimeMs = Date.now();
|
|
32939
33204
|
try {
|
|
32940
|
-
await
|
|
32941
|
-
command:
|
|
33205
|
+
await runPromptCheckCommandExecutor({
|
|
33206
|
+
command: checkCommand,
|
|
32942
33207
|
projectPath: runOptions.projectPath,
|
|
32943
|
-
scriptPath:
|
|
33208
|
+
scriptPath: buildPromptCheckScriptPath(runOptions.scriptPath),
|
|
32944
33209
|
logPath: runOptions.logPath,
|
|
32945
33210
|
preserveArtifactsOnSuccess: runOptions.preserveArtifactsOnSuccess,
|
|
33211
|
+
...(runOptions.signal ? { signal: runOptions.signal } : {}),
|
|
32946
33212
|
});
|
|
33213
|
+
(_b = runOptions.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
|
|
32947
33214
|
return undefined;
|
|
32948
33215
|
}
|
|
32949
33216
|
catch (error) {
|
|
33217
|
+
if (error instanceof CoderCheckSetupError || ((_c = runOptions.signal) === null || _c === void 0 ? void 0 : _c.aborted))
|
|
33218
|
+
throw error;
|
|
32950
33219
|
return { error };
|
|
32951
33220
|
}
|
|
32952
33221
|
finally {
|
|
32953
|
-
stepTracker.finishStep({ kind: '
|
|
33222
|
+
stepTracker.finishStep({ kind: 'checking', usage: null, durationMs: Date.now() - stepStartedTimeMs });
|
|
32954
33223
|
}
|
|
32955
33224
|
}
|
|
32956
33225
|
/**
|
|
@@ -32964,13 +33233,13 @@ async function waitForPromptAttemptPauseCheckpoint(waitForPauseCheckpoint, runne
|
|
|
32964
33233
|
}));
|
|
32965
33234
|
}
|
|
32966
33235
|
/**
|
|
32967
|
-
* Waits for a pause checkpoint immediately before one
|
|
33236
|
+
* Waits for a pause checkpoint immediately before one check command begins.
|
|
32968
33237
|
*/
|
|
32969
|
-
async function
|
|
33238
|
+
async function waitForCheckPauseCheckpoint(waitForPauseCheckpoint, checkCommand, attemptCount) {
|
|
32970
33239
|
await (waitForPauseCheckpoint === null || waitForPauseCheckpoint === void 0 ? void 0 : waitForPauseCheckpoint({
|
|
32971
|
-
checkpointLabel:
|
|
33240
|
+
checkpointLabel: buildCheckPauseLabel(attemptCount),
|
|
32972
33241
|
phase: 'verifying',
|
|
32973
|
-
statusMessage: `Running
|
|
33242
|
+
statusMessage: `Running check after attempt #${attemptCount}: ${checkCommand}`,
|
|
32974
33243
|
}));
|
|
32975
33244
|
}
|
|
32976
33245
|
/**
|
|
@@ -32986,51 +33255,53 @@ function buildPromptAttemptStatusMessage(runnerName, attemptCount) {
|
|
|
32986
33255
|
return `Calling ${runnerName} (attempt ${attemptCount})`;
|
|
32987
33256
|
}
|
|
32988
33257
|
/**
|
|
32989
|
-
* Builds the human-readable pause label used before one
|
|
33258
|
+
* Builds the human-readable pause label used before one check command begins.
|
|
32990
33259
|
*/
|
|
32991
|
-
function
|
|
32992
|
-
return `running
|
|
33260
|
+
function buildCheckPauseLabel(attemptCount) {
|
|
33261
|
+
return `running check after attempt #${attemptCount}`;
|
|
32993
33262
|
}
|
|
32994
33263
|
/**
|
|
32995
|
-
* Builds one feedback block appended to the next coding attempt after
|
|
33264
|
+
* Builds one feedback block appended to the next coding attempt after checks fail.
|
|
32996
33265
|
*/
|
|
32997
|
-
function
|
|
33266
|
+
function buildCheckFeedback({ checkCommand, failedAttemptCount, checkOutput, }) {
|
|
32998
33267
|
const nextAttemptCount = failedAttemptCount + 1;
|
|
32999
33268
|
return spaceTrim((block) => `
|
|
33000
|
-
The previous implementation did not pass the required
|
|
33269
|
+
The previous implementation did not pass the required check command.
|
|
33001
33270
|
|
|
33002
|
-
## Automated
|
|
33003
|
-
- Retry attempt: ${nextAttemptCount} of ${
|
|
33004
|
-
-
|
|
33005
|
-
- Update the current implementation so the
|
|
33271
|
+
## Automated check feedback
|
|
33272
|
+
- Retry attempt: ${nextAttemptCount} of ${MAX_PROMPT_CHECK_ATTEMPTS}
|
|
33273
|
+
- Check command: \`${checkCommand}\`
|
|
33274
|
+
- Update the current implementation so the check command passes without breaking the original task requirements.
|
|
33006
33275
|
|
|
33007
|
-
|
|
33276
|
+
${block(CHECK_REPAIR_INSTRUCTIONS)}
|
|
33277
|
+
|
|
33278
|
+
### Check output
|
|
33008
33279
|
\`\`\`
|
|
33009
|
-
${block(
|
|
33280
|
+
${block(checkOutput)}
|
|
33010
33281
|
\`\`\`
|
|
33011
33282
|
`);
|
|
33012
33283
|
}
|
|
33013
33284
|
/**
|
|
33014
|
-
* Builds the final error message written when
|
|
33285
|
+
* Builds the final error message written when check still fails after all retries.
|
|
33015
33286
|
*/
|
|
33016
|
-
function
|
|
33287
|
+
function buildFinalCheckFailureMessage({ promptLabel, checkCommand, attemptCount, checkOutput, }) {
|
|
33017
33288
|
return spaceTrim((block) => `
|
|
33018
|
-
|
|
33289
|
+
Check command \`${checkCommand}\` failed for \`${promptLabel}\` after ${attemptCount} attempts.
|
|
33019
33290
|
|
|
33020
|
-
###
|
|
33291
|
+
### Check output
|
|
33021
33292
|
\`\`\`
|
|
33022
|
-
${block(
|
|
33293
|
+
${block(checkOutput)}
|
|
33023
33294
|
\`\`\`
|
|
33024
33295
|
`);
|
|
33025
33296
|
}
|
|
33026
33297
|
/**
|
|
33027
|
-
* Derives a dedicated temp-script path for
|
|
33298
|
+
* Derives a dedicated temp-script path for check commands.
|
|
33028
33299
|
*/
|
|
33029
|
-
function
|
|
33300
|
+
function buildPromptCheckScriptPath(scriptPath) {
|
|
33030
33301
|
if (scriptPath.toLowerCase().endsWith(SHELL_SCRIPT_EXTENSION)) {
|
|
33031
|
-
return `${scriptPath.slice(0, -SHELL_SCRIPT_EXTENSION.length)}.
|
|
33302
|
+
return `${scriptPath.slice(0, -SHELL_SCRIPT_EXTENSION.length)}.check.sh`;
|
|
33032
33303
|
}
|
|
33033
|
-
return `${scriptPath}.
|
|
33304
|
+
return `${scriptPath}.check.sh`;
|
|
33034
33305
|
}
|
|
33035
33306
|
|
|
33036
33307
|
/**
|
|
@@ -41930,16 +42201,16 @@ function validateAgentRunOptions(options) {
|
|
|
41930
42201
|
* Answers one queued `.book` message thread and moves it to `messages/finished`.
|
|
41931
42202
|
*/
|
|
41932
42203
|
async function tickAgentMessages(options, tickOptions = {}) {
|
|
41933
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
42204
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
41934
42205
|
validateAgentRunOptions(options);
|
|
41935
|
-
const projectPath = tickOptions.projectPath
|
|
42206
|
+
const projectPath = (_b = (_a = tickOptions.projectPath) !== null && _a !== void 0 ? _a : options.projectPath) !== null && _b !== void 0 ? _b : process.cwd();
|
|
41936
42207
|
let queueSnapshot = await loadAgentMessageQueueSnapshot(projectPath);
|
|
41937
42208
|
let queuedMessage = resolveSelectedQueuedMessage(queueSnapshot, tickOptions.queuedMessage);
|
|
41938
42209
|
if (!queuedMessage) {
|
|
41939
42210
|
announceNoQueuedMessages(tickOptions);
|
|
41940
42211
|
return { isMessageProcessed: false };
|
|
41941
42212
|
}
|
|
41942
|
-
if (tickOptions.uiHandle && !((
|
|
42213
|
+
if (tickOptions.uiHandle && !((_c = tickOptions.uiPresentation) === null || _c === void 0 ? void 0 : _c.isSharedDashboard)) {
|
|
41943
42214
|
updateAgentRunUiForPulling(tickOptions.uiHandle, queueSnapshot, 'Pulling latest changes before answering the next message');
|
|
41944
42215
|
}
|
|
41945
42216
|
const autoPullTimestamp = await pullLatestChangesForAgentQueueIfEnabled({
|
|
@@ -41951,7 +42222,7 @@ async function tickAgentMessages(options, tickOptions = {}) {
|
|
|
41951
42222
|
queueSnapshot = await loadAgentMessageQueueSnapshot(projectPath);
|
|
41952
42223
|
queuedMessage = resolveSelectedQueuedMessage(queueSnapshot, tickOptions.queuedMessage);
|
|
41953
42224
|
if (!queuedMessage) {
|
|
41954
|
-
if (tickOptions.uiHandle && !((
|
|
42225
|
+
if (tickOptions.uiHandle && !((_d = tickOptions.uiPresentation) === null || _d === void 0 ? void 0 : _d.isSharedDashboard)) {
|
|
41955
42226
|
updateAgentRunUiForWatching(tickOptions.uiHandle, queueSnapshot);
|
|
41956
42227
|
}
|
|
41957
42228
|
announceNoQueuedMessages(tickOptions);
|
|
@@ -41970,24 +42241,24 @@ async function tickAgentMessages(options, tickOptions = {}) {
|
|
|
41970
42241
|
actualRunnerModel,
|
|
41971
42242
|
queuedMessage,
|
|
41972
42243
|
uiHandle,
|
|
41973
|
-
isSharedDashboard: (
|
|
42244
|
+
isSharedDashboard: (_e = tickOptions.uiPresentation) === null || _e === void 0 ? void 0 : _e.isSharedDashboard,
|
|
41974
42245
|
});
|
|
41975
|
-
if (!((
|
|
41976
|
-
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(((
|
|
42246
|
+
if (!((_f = tickOptions.uiPresentation) === null || _f === void 0 ? void 0 : _f.isSharedDashboard)) {
|
|
42247
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(((_g = tickOptions.uiPresentation) === null || _g === void 0 ? void 0 : _g.completedProgressStats) ||
|
|
41977
42248
|
createAgentQueueProgressSnapshot({
|
|
41978
42249
|
finishedMessageCount: queueSnapshot.finishedMessageCount + 1,
|
|
41979
42250
|
queuedMessages: removeQueuedMessageFromSnapshot(queueSnapshot, queuedMessage),
|
|
41980
42251
|
}));
|
|
41981
|
-
if ((
|
|
42252
|
+
if ((_h = tickOptions.uiPresentation) === null || _h === void 0 ? void 0 : _h.completedAgentStatusLines) {
|
|
41982
42253
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAgentStatusLines([...tickOptions.uiPresentation.completedAgentStatusLines]);
|
|
41983
42254
|
}
|
|
41984
|
-
if ((
|
|
42255
|
+
if ((_j = tickOptions.uiPresentation) === null || _j === void 0 ? void 0 : _j.completedAgentStatusTableRows) {
|
|
41985
42256
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAgentStatusTableRows([...tickOptions.uiPresentation.completedAgentStatusTableRows]);
|
|
41986
42257
|
}
|
|
41987
|
-
if ((
|
|
42258
|
+
if ((_k = tickOptions.uiPresentation) === null || _k === void 0 ? void 0 : _k.completedMessagePreviewLines) {
|
|
41988
42259
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setMessagePreviewLines([...tickOptions.uiPresentation.completedMessagePreviewLines]);
|
|
41989
42260
|
}
|
|
41990
|
-
if ((
|
|
42261
|
+
if ((_l = tickOptions.uiPresentation) === null || _l === void 0 ? void 0 : _l.completedMessagePreviewSections) {
|
|
41991
42262
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setMessagePreviewSections([
|
|
41992
42263
|
...tickOptions.uiPresentation.completedMessagePreviewSections,
|
|
41993
42264
|
]);
|
|
@@ -42071,7 +42342,7 @@ async function runQueuedAgentMessage(options) {
|
|
|
42071
42342
|
try {
|
|
42072
42343
|
try {
|
|
42073
42344
|
promptRunResult = await withPromptRuntimeLog(scriptPath, async (logPath) => {
|
|
42074
|
-
const runResult = await
|
|
42345
|
+
const runResult = await runPromptWithCheckFeedback({
|
|
42075
42346
|
runner,
|
|
42076
42347
|
prompt,
|
|
42077
42348
|
scriptPath,
|
|
@@ -42498,12 +42769,12 @@ const MULTI_AGENT_QUEUE_POLL_INTERVAL_MS = 2000;
|
|
|
42498
42769
|
* Watches all direct child agent repositories from the current directory in one shared session.
|
|
42499
42770
|
*/
|
|
42500
42771
|
async function runMultipleAgentMessages(options, controls = {}) {
|
|
42501
|
-
var _a, _b;
|
|
42772
|
+
var _a, _b, _c;
|
|
42502
42773
|
validateAgentRunOptions(options);
|
|
42503
42774
|
validateAgentWatchOptions('ptbk agent-folder run-multiple', options);
|
|
42504
|
-
const rootPath = process.cwd();
|
|
42775
|
+
const rootPath = (_a = options.projectPath) !== null && _a !== void 0 ? _a : process.cwd();
|
|
42505
42776
|
const shouldContinue = controls.shouldContinue || (() => just(true));
|
|
42506
|
-
const queuePollIntervalMs = (
|
|
42777
|
+
const queuePollIntervalMs = (_b = controls.queuePollIntervalMs) !== null && _b !== void 0 ? _b : MULTI_AGENT_QUEUE_POLL_INTERVAL_MS;
|
|
42507
42778
|
const watchErrorLogDirectoryPath = controls.watchErrorLogDirectoryPath || rootPath;
|
|
42508
42779
|
const ignoreMatcher = createAgentIgnoreMatcher(options.ignorePatterns);
|
|
42509
42780
|
const githubSynchronizer = new MultipleAgentGithubSynchronizer();
|
|
@@ -42527,7 +42798,7 @@ async function runMultipleAgentMessages(options, controls = {}) {
|
|
|
42527
42798
|
watchErrorLogDirectoryPath,
|
|
42528
42799
|
});
|
|
42529
42800
|
isWatchSessionInitialized = true;
|
|
42530
|
-
(
|
|
42801
|
+
(_c = controls.onUiInitialized) === null || _c === void 0 ? void 0 : _c.call(controls, uiPresenter.uiHandle);
|
|
42531
42802
|
if (!uiPresenter.uiHandle) {
|
|
42532
42803
|
console.info(colors.green('Watching direct child agent repositories for queued messages.'));
|
|
42533
42804
|
}
|
|
@@ -43786,6 +44057,7 @@ const WORKSPACE_REPOSITORY_DESCRIPTION = spaceTrim$1(`
|
|
|
43786
44057
|
* @private internal registration helper for workspace CLI commands
|
|
43787
44058
|
*/
|
|
43788
44059
|
function addWorkspaceRepositoryOptions(command) {
|
|
44060
|
+
addProjectPathOption(command);
|
|
43789
44061
|
if (!command.options.some((option) => option.long === '--no-questions'))
|
|
43790
44062
|
addQuestionsOption(command);
|
|
43791
44063
|
command.addHelpText('after', `\n${WORKSPACE_REPOSITORY_DESCRIPTION}\n`);
|
|
@@ -43887,17 +44159,7 @@ const EXECUTE_FILE = promisify(execFile);
|
|
|
43887
44159
|
* @private shared workspace discovery for CLI commands
|
|
43888
44160
|
*/
|
|
43889
44161
|
async function $resolveWorkspaceRepository(projectDirectory = process.cwd()) {
|
|
43890
|
-
const
|
|
43891
|
-
let projectPath;
|
|
43892
|
-
try {
|
|
43893
|
-
projectPath = await realpath(requestedPath);
|
|
43894
|
-
if (!(await stat(projectPath)).isDirectory()) {
|
|
43895
|
-
throw new EnvironmentMismatchError(`The project path \`${requestedPath}\` is not a directory.`);
|
|
43896
|
-
}
|
|
43897
|
-
}
|
|
43898
|
-
catch (error) {
|
|
43899
|
-
throw new EnvironmentMismatchError(spaceTrim$1(`Cannot access project directory \`${requestedPath}\`. Check that it exists and is accessible.\n\n${describeWorkspaceError(error)}`));
|
|
43900
|
-
}
|
|
44162
|
+
const projectPath = await resolveProjectDirectory(projectDirectory);
|
|
43901
44163
|
return $inspectWorkspaceRepository(projectPath);
|
|
43902
44164
|
}
|
|
43903
44165
|
/**
|
|
@@ -44009,7 +44271,7 @@ async function $inspectWorkspaceRepository(projectPath) {
|
|
|
44009
44271
|
// Git may skip damaged inner metadata and find a valid parent. Do not silently use that parent
|
|
44010
44272
|
// for a project whose own checkout needs repair.
|
|
44011
44273
|
await $assertNoBrokenRepositoryMetadata(projectPath, repositoryRoot);
|
|
44012
|
-
const gitDirectory = (await $runWorkspaceGit(projectPath, ['rev-parse', '--absolute-git-dir'])).trim();
|
|
44274
|
+
const gitDirectory = await realpath((await $runWorkspaceGit(projectPath, ['rev-parse', '--absolute-git-dir'])).trim());
|
|
44013
44275
|
// Also validate the index and metadata, without refreshing the index or depending on an existing commit.
|
|
44014
44276
|
await $runWorkspaceGit(projectPath, ['status', '--porcelain', '--untracked-files=no']);
|
|
44015
44277
|
return { projectPath, repositoryRoot, gitDirectory, repositoryStatus: 'reused' };
|
|
@@ -44337,10 +44599,15 @@ function $initializeCoderAddCommand(program) {
|
|
|
44337
44599
|
addQuestionsOption(command);
|
|
44338
44600
|
addWorkspaceRepositoryOptions(command);
|
|
44339
44601
|
command.action(handleActionErrors(async (descriptionArgument, cliOptions) => {
|
|
44602
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
44340
44603
|
const { priority, template: templateOption } = cliOptions;
|
|
44341
44604
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
44342
44605
|
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
44343
|
-
const workspace = await $preflightWorkspaceRepository({
|
|
44606
|
+
const workspace = await $preflightWorkspaceRepository({
|
|
44607
|
+
...projectOptions,
|
|
44608
|
+
policy: 'mutate',
|
|
44609
|
+
...questionsOptions,
|
|
44610
|
+
});
|
|
44344
44611
|
const { projectPath } = workspace;
|
|
44345
44612
|
const description = await resolveCoderPromptDescription(descriptionArgument, questionsOptions);
|
|
44346
44613
|
// Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
|
|
@@ -44563,7 +44830,9 @@ function $initializeCoderFindFreshEmojiTagCommand(program) {
|
|
|
44563
44830
|
`));
|
|
44564
44831
|
addWorkspaceRepositoryOptions(command);
|
|
44565
44832
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
44833
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
44566
44834
|
const workspace = await $preflightWorkspaceRepository({
|
|
44835
|
+
...projectOptions,
|
|
44567
44836
|
policy: 'read-only',
|
|
44568
44837
|
isAskingQuestionsEnabled: cliOptions.questions,
|
|
44569
44838
|
});
|
|
@@ -44804,8 +45073,10 @@ function $initializeCoderFindRefactorCandidatesCommand(program) {
|
|
|
44804
45073
|
command.option('--limit <candidate-count>', 'Create at most this many refactor prompts, keeping the most important candidates', createPositiveIntegerOptionParser('--limit'));
|
|
44805
45074
|
addWorkspaceRepositoryOptions(command);
|
|
44806
45075
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
45076
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
44807
45077
|
const { level = DEFAULT_REFACTOR_CANDIDATE_LEVEL, limit } = cliOptions;
|
|
44808
45078
|
const workspace = await $preflightWorkspaceRepository({
|
|
45079
|
+
...projectOptions,
|
|
44809
45080
|
policy: 'mutate',
|
|
44810
45081
|
isAskingQuestionsEnabled: cliOptions.questions,
|
|
44811
45082
|
});
|
|
@@ -44839,8 +45110,10 @@ function $initializeCoderFindUnwrittenCommand(program) {
|
|
|
44839
45110
|
command.option('--priority <minimum-priority>', 'Filter prompts by minimum priority level', parseIntOption, 0);
|
|
44840
45111
|
addWorkspaceRepositoryOptions(command);
|
|
44841
45112
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
45113
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
44842
45114
|
const { priority = 0 } = cliOptions;
|
|
44843
45115
|
const workspace = await $preflightWorkspaceRepository({
|
|
45116
|
+
...projectOptions,
|
|
44844
45117
|
policy: 'read-only',
|
|
44845
45118
|
isAskingQuestionsEnabled: cliOptions.questions,
|
|
44846
45119
|
});
|
|
@@ -44994,10 +45267,12 @@ function $initializeCoderGenerateBoilerplatesCommand(program) {
|
|
|
44994
45267
|
addCoderGitSyncOptions(command);
|
|
44995
45268
|
addWorkspaceRepositoryOptions(command);
|
|
44996
45269
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
45270
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
44997
45271
|
const { count: countOption, template: templateOption } = cliOptions;
|
|
44998
45272
|
const boilerplateCount = parseBoilerplateCount(countOption);
|
|
44999
45273
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
45000
45274
|
const workspace = await $preflightWorkspaceRepository({
|
|
45275
|
+
...projectOptions,
|
|
45001
45276
|
policy: 'mutate',
|
|
45002
45277
|
isAskingQuestionsEnabled: cliOptions.questions,
|
|
45003
45278
|
});
|
|
@@ -46036,16 +46311,16 @@ const CODER_REFERENCED_ARTIFACT_DEFINITIONS = [
|
|
|
46036
46311
|
...getDefaultCoderProjectPromptTemplateDefinitions().map(createCoderPromptTemplateArtifactDefinition),
|
|
46037
46312
|
];
|
|
46038
46313
|
/**
|
|
46039
|
-
* Initializes artifacts referenced by freshly added scripts.
|
|
46314
|
+
* Initializes essential context and artifacts referenced by freshly added scripts. Books are ensured separately.
|
|
46040
46315
|
*
|
|
46041
|
-
*
|
|
46316
|
+
* AGENTS.md is essential even when every script already exists or uses implicit defaults.
|
|
46042
46317
|
*
|
|
46043
46318
|
* @private function of `initializeCoderProjectConfiguration`
|
|
46044
46319
|
*/
|
|
46045
46320
|
async function ensureCoderReferencedArtifacts(projectPath, referencedArtifactPaths) {
|
|
46046
46321
|
const ensuredArtifacts = [];
|
|
46047
46322
|
for (const { relativeFilePath, ensureArtifactFile } of CODER_REFERENCED_ARTIFACT_DEFINITIONS) {
|
|
46048
|
-
if (!referencedArtifactPaths.has(relativeFilePath)) {
|
|
46323
|
+
if (relativeFilePath !== AGENTS_FILE_PATH && !referencedArtifactPaths.has(relativeFilePath)) {
|
|
46049
46324
|
ensuredArtifacts.push({ relativeFilePath, status: 'not-referenced' });
|
|
46050
46325
|
continue;
|
|
46051
46326
|
}
|
|
@@ -46664,7 +46939,7 @@ async function ensureCoderGitignoreRules(projectPath, rules) {
|
|
|
46664
46939
|
/**
|
|
46665
46940
|
* Name of the npm script which `ptbk coder run` uses to verify the project.
|
|
46666
46941
|
*/
|
|
46667
|
-
const
|
|
46942
|
+
const CHECK_SCRIPT_NAME = 'check';
|
|
46668
46943
|
/**
|
|
46669
46944
|
* Default npm scripts initialized by `ptbk coder init`.
|
|
46670
46945
|
*
|
|
@@ -46684,14 +46959,13 @@ const DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS = [
|
|
|
46684
46959
|
{
|
|
46685
46960
|
scriptName: 'coder:plan',
|
|
46686
46961
|
scriptCommand: 'npx ptbk coder plan --harness openai-codex',
|
|
46687
|
-
referencedArtifactPaths: [
|
|
46962
|
+
referencedArtifactPaths: [CODER_DEVELOPER_AGENT_FILE_PATH, AGENTS_FILE_PATH, COMMON_PROMPT_TEMPLATE_FILE_PATH],
|
|
46688
46963
|
},
|
|
46689
46964
|
{
|
|
46690
46965
|
scriptName: 'coder:run',
|
|
46691
46966
|
scriptCommand: [
|
|
46692
46967
|
'npx ptbk coder run --harness openai-codex --thinking-level max',
|
|
46693
|
-
`--
|
|
46694
|
-
`--test "npm run ${CODER_TEST_SCRIPT_NAME}" --test-before yes-and-fix`,
|
|
46968
|
+
`--check "npm run ${CHECK_SCRIPT_NAME}" --check-before yes-and-fix`,
|
|
46695
46969
|
].join(' '),
|
|
46696
46970
|
referencedArtifactPaths: [CODER_DEVELOPER_AGENT_FILE_PATH, AGENTS_FILE_PATH],
|
|
46697
46971
|
},
|
|
@@ -46704,8 +46978,8 @@ const DEFAULT_CODER_PACKAGE_JSON_SCRIPT_DEFINITIONS = [
|
|
|
46704
46978
|
{
|
|
46705
46979
|
// Note: The verification command of `coder:run` is a project-owned script, so every project can decide
|
|
46706
46980
|
// what "verified" means without touching the `coder:run` script itself
|
|
46707
|
-
scriptName:
|
|
46708
|
-
scriptCommand:
|
|
46981
|
+
scriptName: CHECK_SCRIPT_NAME,
|
|
46982
|
+
scriptCommand: CHECK_SETUP_PLACEHOLDER_COMMAND,
|
|
46709
46983
|
referencedArtifactPaths: [],
|
|
46710
46984
|
},
|
|
46711
46985
|
];
|
|
@@ -46770,12 +47044,13 @@ const DEFAULT_JSON_FILE_NEWLINE = '\n';
|
|
|
46770
47044
|
/**
|
|
46771
47045
|
* Ensures one JSON object field contains the provided string-record entries.
|
|
46772
47046
|
*
|
|
46773
|
-
* Entries
|
|
46774
|
-
*
|
|
47047
|
+
* Entries are additive unless a caller explicitly supplies a scoped migration callback.
|
|
47048
|
+
* Hand-tuned scripts and settings survive repeated `ptbk coder init`; migrations recognize generated entries only.
|
|
46775
47049
|
*
|
|
46776
47050
|
* @private function of `initializeCoderProjectConfiguration`
|
|
46777
47051
|
*/
|
|
46778
|
-
async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldPath, nextEntries, ensureParentDirectoryPath, }) {
|
|
47052
|
+
async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldPath, nextEntries, ensureParentDirectoryPath, transformExistingEntries, }) {
|
|
47053
|
+
var _a;
|
|
46779
47054
|
if (ensureParentDirectoryPath) {
|
|
46780
47055
|
await mkdir(join(projectPath, ensureParentDirectoryPath), { recursive: true });
|
|
46781
47056
|
}
|
|
@@ -46785,7 +47060,7 @@ async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldP
|
|
|
46785
47060
|
const jsonObject = fileContent === undefined ? {} : await parseJsonObjectFile(relativeFilePath, fileContent);
|
|
46786
47061
|
const existingEntries = getStringRecordOrDefault(jsonObject[fieldPath], relativeFilePath, fieldPath);
|
|
46787
47062
|
const addedEntryKeys = [];
|
|
46788
|
-
const mergedEntries = { ...existingEntries };
|
|
47063
|
+
const mergedEntries = { ...((_a = (await (transformExistingEntries === null || transformExistingEntries === void 0 ? void 0 : transformExistingEntries(existingEntries)))) !== null && _a !== void 0 ? _a : existingEntries) };
|
|
46789
47064
|
for (const [entryKey, entryValue] of Object.entries(nextEntries)) {
|
|
46790
47065
|
if (Object.prototype.hasOwnProperty.call(mergedEntries, entryKey)) {
|
|
46791
47066
|
// Note: The project already defines this entry, keep its own value untouched
|
|
@@ -46794,7 +47069,12 @@ async function mergeStringRecordJsonFile({ projectPath, relativeFilePath, fieldP
|
|
|
46794
47069
|
mergedEntries[entryKey] = entryValue;
|
|
46795
47070
|
addedEntryKeys.push(entryKey);
|
|
46796
47071
|
}
|
|
46797
|
-
const
|
|
47072
|
+
for (const entryKey of Object.keys(mergedEntries)) {
|
|
47073
|
+
if (!Object.prototype.hasOwnProperty.call(existingEntries, entryKey) && !addedEntryKeys.includes(entryKey)) {
|
|
47074
|
+
addedEntryKeys.push(entryKey);
|
|
47075
|
+
}
|
|
47076
|
+
}
|
|
47077
|
+
const hasChanges = fileContent === undefined || JSON.stringify(mergedEntries) !== JSON.stringify(existingEntries);
|
|
46798
47078
|
if (!hasChanges) {
|
|
46799
47079
|
return { status: 'unchanged', addedEntryKeys };
|
|
46800
47080
|
}
|
|
@@ -46883,6 +47163,301 @@ function isPlainObject$1(value) {
|
|
|
46883
47163
|
}
|
|
46884
47164
|
// Note: [🟡] Code for coder init JSON merging [mergeStringRecordJsonFile](src/cli/cli-commands/coder/mergeStringRecordJsonFile.ts) should never be published outside of `@promptbook/cli`
|
|
46885
47165
|
|
|
47166
|
+
/** Old initialized aggregate entries, used only at this migration boundary. */
|
|
47167
|
+
const LEGACY_CHECK_SCRIPT_NAMES = ['test-for-ptbk-coder', 'check-for-ptbk-coder'];
|
|
47168
|
+
/** Conventional project validation scripts, ordered from lightweight checks to tests. */
|
|
47169
|
+
const VALIDATION_SCRIPT_GROUPS = [
|
|
47170
|
+
['lint', 'test-lint'],
|
|
47171
|
+
['typecheck', 'type-check', 'type-checking', 'check-types', 'test-types'],
|
|
47172
|
+
['build', 'test-build'],
|
|
47173
|
+
];
|
|
47174
|
+
/** Conventional leaf test families used when the project has no usable test aggregate. */
|
|
47175
|
+
const TEST_SCRIPT_GROUPS = [
|
|
47176
|
+
['test-unit', 'test:unit'],
|
|
47177
|
+
['test-integration', 'test:integration'],
|
|
47178
|
+
['test-e2e', 'test:e2e'],
|
|
47179
|
+
];
|
|
47180
|
+
/** Script names that must never be reached by a generated aggregate. */
|
|
47181
|
+
const NON_VALIDATION_SCRIPT_PATTERN = /^(?:check$|coder:|(?:dev|start|serve|watch|deploy|publish|install|preinstall|postinstall|prepare|reset|clean)(?:$|[:-]))/iu;
|
|
47182
|
+
/** Clearly unsuitable shell bodies are excluded even under a conventional validation name. */
|
|
47183
|
+
const UNSUITABLE_VALIDATION_BODY_PATTERN = /(?:\b(?:ptbk|promptbook)\s+coder\s+(?:run|fix)|\bcoder:(?:run|fix)\b|--watch(?:All)?(?:\b|=)|\b(?:watch|nodemon|concurrently|serve|deploy|publish|install|reset|rm|rmdir|del|remove-item)\b|--if-present|\|\||(?:^|[^&])&(?:$|[^&])|;|\bexit\s+0\b)/iu;
|
|
47184
|
+
/** Npm lifecycle hooks that run implicitly before and after a selected project script. */
|
|
47185
|
+
const SCRIPT_LIFECYCLE_PREFIXES = ['pre', 'post'];
|
|
47186
|
+
/**
|
|
47187
|
+
* Preserves project scripts, creates one canonical check, and migrates only exact generated caller forms.
|
|
47188
|
+
* @private shared package-script preparation for Coder initialization
|
|
47189
|
+
*/
|
|
47190
|
+
function prepareCoderPackageJsonScripts(existing, externalCallers = {}) {
|
|
47191
|
+
var _a;
|
|
47192
|
+
const scripts = { ...existing };
|
|
47193
|
+
const migrationInstructions = [];
|
|
47194
|
+
const legacyNames = LEGACY_CHECK_SCRIPT_NAMES.filter((name) => Object.prototype.hasOwnProperty.call(existing, name));
|
|
47195
|
+
let checkScriptSummary;
|
|
47196
|
+
if (Object.prototype.hasOwnProperty.call(existing, 'check')) {
|
|
47197
|
+
checkScriptSummary = 'Preserved project scripts.check exactly; Coder executes npm run check.';
|
|
47198
|
+
}
|
|
47199
|
+
else if (legacyNames.length > 0) {
|
|
47200
|
+
const sourceName = legacyNames[0];
|
|
47201
|
+
const isRecursive = scriptReaches(sourceName, 'check', existing, new Set()) ||
|
|
47202
|
+
scriptReaches(sourceName, sourceName, existing, new Set()) ||
|
|
47203
|
+
scriptReaches(sourceName, 'coder:run', existing, new Set()) ||
|
|
47204
|
+
scriptReaches(sourceName, 'coder:fix', existing, new Set());
|
|
47205
|
+
const conflictingLifecycleNames = SCRIPT_LIFECYCLE_PREFIXES.filter((prefix) => existing[`${prefix}check`] !== undefined &&
|
|
47206
|
+
existing[`${prefix}${sourceName}`] !== existing[`${prefix}check`]).map((prefix) => `${prefix}check`);
|
|
47207
|
+
scripts.check =
|
|
47208
|
+
isRecursive || conflictingLifecycleNames.length > 0
|
|
47209
|
+
? CHECK_SETUP_PLACEHOLDER_COMMAND
|
|
47210
|
+
: existing[sourceName];
|
|
47211
|
+
if (!isRecursive && conflictingLifecycleNames.length === 0) {
|
|
47212
|
+
// npm runs these hooks implicitly. Preserve their bodies as well as the main script's scope.
|
|
47213
|
+
for (const prefix of SCRIPT_LIFECYCLE_PREFIXES) {
|
|
47214
|
+
const legacyHook = existing[`${prefix}${sourceName}`];
|
|
47215
|
+
if (legacyHook !== undefined)
|
|
47216
|
+
scripts[`${prefix}check`] = legacyHook;
|
|
47217
|
+
}
|
|
47218
|
+
}
|
|
47219
|
+
checkScriptSummary = isRecursive
|
|
47220
|
+
? `Kept recursive scripts.${sourceName} unchanged; configure scripts.check with validation that does not call check or Coder recursively.`
|
|
47221
|
+
: conflictingLifecycleNames.length > 0
|
|
47222
|
+
? `Kept scripts.${sourceName} and conflicting ${conflictingLifecycleNames.join(', ')} hooks unchanged; configure scripts.check and its lifecycle hooks to preserve the required validation.`
|
|
47223
|
+
: `Preserved scripts.${sourceName}'s validation command and npm lifecycle hooks in scripts.check: ${scripts.check}`;
|
|
47224
|
+
}
|
|
47225
|
+
else {
|
|
47226
|
+
const selectedScripts = selectValidationScripts(existing);
|
|
47227
|
+
scripts.check =
|
|
47228
|
+
selectedScripts.length > 0
|
|
47229
|
+
? selectedScripts.map((name) => (name === 'test' ? 'npm test' : `npm run ${name}`)).join(' && ')
|
|
47230
|
+
: CHECK_SETUP_PLACEHOLDER_COMMAND;
|
|
47231
|
+
checkScriptSummary =
|
|
47232
|
+
selectedScripts.length > 0
|
|
47233
|
+
? `Generated scripts.check from the available validation scripts (${selectedScripts.join(', ')}): ${scripts.check}`
|
|
47234
|
+
: 'No usable validation scripts found. scripts.check contains a failing setup placeholder; configure it before running Coder.';
|
|
47235
|
+
}
|
|
47236
|
+
for (const [name, command] of Object.entries(existing)) {
|
|
47237
|
+
if (['check', ...legacyNames].some((verificationName) => name === verificationName ||
|
|
47238
|
+
SCRIPT_LIFECYCLE_PREFIXES.some((prefix) => name === `${prefix}${verificationName}`)))
|
|
47239
|
+
continue;
|
|
47240
|
+
const migratedCaller = migrateGeneratedCoderRunScript(command);
|
|
47241
|
+
if (migratedCaller !== undefined) {
|
|
47242
|
+
// A different existing check is authoritative, but changing a custom legacy caller's scope is not safe.
|
|
47243
|
+
const referencedLegacyName = legacyNames.find((legacyName) => command.includes(legacyName));
|
|
47244
|
+
const isConflictingCustomCheck = referencedLegacyName !== undefined &&
|
|
47245
|
+
!isLegacyCheckScopePreserved(referencedLegacyName, scripts) &&
|
|
47246
|
+
!isUnchangedLegacyCheckDefault(referencedLegacyName, scripts);
|
|
47247
|
+
if (!isConflictingCustomCheck)
|
|
47248
|
+
scripts[name] = migratedCaller;
|
|
47249
|
+
}
|
|
47250
|
+
}
|
|
47251
|
+
for (const legacyName of legacyNames) {
|
|
47252
|
+
const callers = Object.entries(scripts)
|
|
47253
|
+
.filter(([name, command]) => name !== legacyName && command.includes(legacyName))
|
|
47254
|
+
.map(([name]) => name);
|
|
47255
|
+
const isPreservedScope = isLegacyCheckScopePreserved(legacyName, scripts);
|
|
47256
|
+
const isObsoleteGeneratedDefault = isUnchangedLegacyCheckDefault(legacyName, scripts) && !isCheckSetupRequired(scripts.check);
|
|
47257
|
+
const files = (_a = externalCallers[legacyName]) !== null && _a !== void 0 ? _a : [];
|
|
47258
|
+
if (callers.length === 0 && files.length === 0 && (isPreservedScope || isObsoleteGeneratedDefault)) {
|
|
47259
|
+
delete scripts[legacyName];
|
|
47260
|
+
for (const prefix of SCRIPT_LIFECYCLE_PREFIXES)
|
|
47261
|
+
delete scripts[`${prefix}${legacyName}`];
|
|
47262
|
+
}
|
|
47263
|
+
else {
|
|
47264
|
+
migrationInstructions.push(`Kept scripts.${legacyName}${callers.length ? `; referenced by scripts.${callers.join(', scripts.')}` : ''}${files.length ? `; referenced by ${files.join(', ')}` : ''}${!isPreservedScope && !isObsoleteGeneratedDefault
|
|
47265
|
+
? '; its custom command or npm lifecycle hooks differ from scripts.check'
|
|
47266
|
+
: ''}. Preserve its required validation and pre/post hooks in scripts.check, update those callers to npm run check, then remove scripts.${legacyName} and its unused lifecycle hooks.`);
|
|
47267
|
+
}
|
|
47268
|
+
}
|
|
47269
|
+
for (const [name, command] of Object.entries(scripts)) {
|
|
47270
|
+
if (/\b(?:ptbk|promptbook)\s+coder\s+(?:run|server)\b|\brun-codex-prompts\b/u.test(command) &&
|
|
47271
|
+
/--test(?:-before)?(?:\s|=|$)/u.test(command)) {
|
|
47272
|
+
migrationInstructions.push(`Update scripts.${name}: replace --test with --check and --test-before with --check-before; review its shell expression manually. Existing command was preserved: ${command}`);
|
|
47273
|
+
}
|
|
47274
|
+
}
|
|
47275
|
+
let isCheckConfigured = true;
|
|
47276
|
+
try {
|
|
47277
|
+
assertProjectCheckScriptsAreConfigured(scripts);
|
|
47278
|
+
}
|
|
47279
|
+
catch (error) {
|
|
47280
|
+
if (!(error instanceof CoderCheckSetupError))
|
|
47281
|
+
throw error;
|
|
47282
|
+
isCheckConfigured = false;
|
|
47283
|
+
checkScriptSummary += ` Additional setup required: ${error.message}`;
|
|
47284
|
+
}
|
|
47285
|
+
return {
|
|
47286
|
+
scripts,
|
|
47287
|
+
checkScriptSummary,
|
|
47288
|
+
migrationInstructions,
|
|
47289
|
+
isCheckConfigured,
|
|
47290
|
+
};
|
|
47291
|
+
}
|
|
47292
|
+
/** Determines whether both the legacy command and its implicit npm validation hooks have been preserved. */
|
|
47293
|
+
function isLegacyCheckScopePreserved(name, scripts) {
|
|
47294
|
+
return (scripts[name] === scripts.check &&
|
|
47295
|
+
SCRIPT_LIFECYCLE_PREFIXES.every((prefix) => scripts[`${prefix}${name}`] === scripts[`${prefix}check`]));
|
|
47296
|
+
}
|
|
47297
|
+
/** Recognizes the generated default only when no custom lifecycle hooks extend its validation scope. */
|
|
47298
|
+
function isUnchangedLegacyCheckDefault(name, scripts) {
|
|
47299
|
+
return (scripts[name] === 'npm test' &&
|
|
47300
|
+
SCRIPT_LIFECYCLE_PREFIXES.every((prefix) => scripts[`${prefix}${name}`] === undefined));
|
|
47301
|
+
}
|
|
47302
|
+
/**
|
|
47303
|
+
* Recognizes unchanged generated run scripts, including the previous explicit Developer/context defaults.
|
|
47304
|
+
* Unknown shell expressions and custom harness configuration are preserved for manual migration.
|
|
47305
|
+
*/
|
|
47306
|
+
function migrateGeneratedCoderRunScript(command) {
|
|
47307
|
+
const prefix = 'npx ptbk coder run --harness openai-codex --thinking-level max';
|
|
47308
|
+
const defaultArguments = ['', ' --agent agents/developer.book --context AGENTS.md'];
|
|
47309
|
+
const verificationArguments = [
|
|
47310
|
+
' --test-before yes-and-fix',
|
|
47311
|
+
...LEGACY_CHECK_SCRIPT_NAMES.map((name) => ` --test "npm run ${name}" --test-before yes-and-fix`),
|
|
47312
|
+
...LEGACY_CHECK_SCRIPT_NAMES.map((name) => ` --check "npm run ${name}" --check-before yes-and-fix`),
|
|
47313
|
+
];
|
|
47314
|
+
const isGenerated = defaultArguments.some((defaults) => verificationArguments.some((verification) => command === prefix + defaults + verification));
|
|
47315
|
+
return isGenerated ? getDefaultCoderPackageJsonScripts()['coder:run'] : undefined;
|
|
47316
|
+
}
|
|
47317
|
+
/** Selects safe conventional scripts, avoiding duplicates already reached by another selected aggregate. */
|
|
47318
|
+
function selectValidationScripts(scripts) {
|
|
47319
|
+
if (SCRIPT_LIFECYCLE_PREFIXES.some((prefix) => scripts[`${prefix}check`] !== undefined &&
|
|
47320
|
+
!isUsableValidationScript(`${prefix}check`, scripts, new Set())))
|
|
47321
|
+
return [];
|
|
47322
|
+
const selected = [];
|
|
47323
|
+
for (const group of VALIDATION_SCRIPT_GROUPS) {
|
|
47324
|
+
const name = group.find((candidate) => isUsableValidationScript(candidate, scripts, new Set()));
|
|
47325
|
+
if (name !== undefined)
|
|
47326
|
+
selected.push(name);
|
|
47327
|
+
}
|
|
47328
|
+
if (isUsableValidationScript('test', scripts, new Set()))
|
|
47329
|
+
selected.push('test');
|
|
47330
|
+
else
|
|
47331
|
+
for (const group of TEST_SCRIPT_GROUPS) {
|
|
47332
|
+
const name = group.find((candidate) => isUsableValidationScript(candidate, scripts, new Set()));
|
|
47333
|
+
if (name !== undefined)
|
|
47334
|
+
selected.push(name);
|
|
47335
|
+
}
|
|
47336
|
+
return selected.filter((name) => !selected.some((other) => other !== name && scriptReaches(other, name, scripts, new Set())));
|
|
47337
|
+
}
|
|
47338
|
+
/** Inspects each body, referenced script, and implicit lifecycle hook before including it in an aggregate. */
|
|
47339
|
+
function isUsableValidationScript(name, scripts, visited) {
|
|
47340
|
+
const command = scripts[name];
|
|
47341
|
+
if (!command ||
|
|
47342
|
+
visited.has(name) ||
|
|
47343
|
+
NON_VALIDATION_SCRIPT_PATTERN.test(name) ||
|
|
47344
|
+
isCheckSetupRequired(command) ||
|
|
47345
|
+
UNSUITABLE_VALIDATION_BODY_PATTERN.test(command))
|
|
47346
|
+
return false;
|
|
47347
|
+
if (command.split('&&').every((part) => /^\s*(?:echo|printf|true|:)(?:\s|$)/iu.test(part)) ||
|
|
47348
|
+
/\bprocess\.exit\(\s*0\s*\)/u.test(command))
|
|
47349
|
+
return false;
|
|
47350
|
+
if (/\b(?:vite|next|astro|webpack-dev-server)\s+(?:dev|start|serve)\b/iu.test(command) ||
|
|
47351
|
+
/(?:^|&&)\s*(?:vite|webpack-dev-server)(?:\s*$|\s+--)/iu.test(command) ||
|
|
47352
|
+
(/\bvitest\b/iu.test(command) && !/\bvitest\s+run\b/iu.test(command)))
|
|
47353
|
+
return false;
|
|
47354
|
+
const nextVisited = new Set([...visited, name]);
|
|
47355
|
+
const references = projectScriptReferences(command);
|
|
47356
|
+
// Ambiguous package-manager flags and cwd switches cannot be composed confidently as root validation.
|
|
47357
|
+
if (/\b(?:npm|pnpm|yarn)\s+(?:--|run(?:-script)?\s+--)/u.test(command) ||
|
|
47358
|
+
(/\b(?:npm|pnpm|yarn)\b/u.test(command) && references.length === 0))
|
|
47359
|
+
return false;
|
|
47360
|
+
if (references.some((reference) => !isUsableValidationScript(reference, scripts, nextVisited)))
|
|
47361
|
+
return false;
|
|
47362
|
+
return SCRIPT_LIFECYCLE_PREFIXES.every((prefix) => {
|
|
47363
|
+
const lifecycleName = `${prefix}${name}`;
|
|
47364
|
+
return scripts[lifecycleName] === undefined || isUsableValidationScript(lifecycleName, scripts, nextVisited);
|
|
47365
|
+
});
|
|
47366
|
+
}
|
|
47367
|
+
/** Checks whether a selected aggregate already reaches another selected script. */
|
|
47368
|
+
function scriptReaches(name, target, scripts, visited) {
|
|
47369
|
+
var _a;
|
|
47370
|
+
if (visited.has(name))
|
|
47371
|
+
return false;
|
|
47372
|
+
const nextVisited = new Set([...visited, name]);
|
|
47373
|
+
const command = (_a = scripts[name]) !== null && _a !== void 0 ? _a : '';
|
|
47374
|
+
if ((target === 'coder:run' && /\b(?:ptbk|promptbook)\s+coder\s+run\b/u.test(command)) ||
|
|
47375
|
+
(target === 'coder:fix' && /\b(?:ptbk|promptbook)\s+coder\s+fix\b/u.test(command)))
|
|
47376
|
+
return true;
|
|
47377
|
+
const references = [
|
|
47378
|
+
...projectScriptReferences(command),
|
|
47379
|
+
...SCRIPT_LIFECYCLE_PREFIXES.map((prefix) => `${prefix}${name}`).filter((lifecycleName) => scripts[lifecycleName] !== undefined),
|
|
47380
|
+
];
|
|
47381
|
+
return references.some((reference) => reference === target || scriptReaches(reference, target, scripts, nextVisited));
|
|
47382
|
+
}
|
|
47383
|
+
|
|
47384
|
+
// cspell:ignore Procfile
|
|
47385
|
+
/** Runtime/dependency/history directories do not contain maintained project callers. */
|
|
47386
|
+
const IGNORED_CALLER_DIRECTORIES = new Set([
|
|
47387
|
+
'node_modules',
|
|
47388
|
+
'.git',
|
|
47389
|
+
'.promptbook',
|
|
47390
|
+
'.next',
|
|
47391
|
+
'.tmp',
|
|
47392
|
+
'dist',
|
|
47393
|
+
'build',
|
|
47394
|
+
'coverage',
|
|
47395
|
+
]);
|
|
47396
|
+
/** Only Coder's known task-history paths are excluded; the same names elsewhere can hold active callers. */
|
|
47397
|
+
const IGNORED_CALLER_HISTORY_PATHS = new Set(['prompts/done', 'prompts/traces']);
|
|
47398
|
+
/** Source and workflow files whose references must be preserved during npm script migration. */
|
|
47399
|
+
const CALLER_FILE_PATTERN = /\.(?:[cm]?jsx?|tsx?|json|ya?ml|md|sh|bash|ps1|cmd|bat|py|toml|xml|groovy)$/iu;
|
|
47400
|
+
/** Conventional workflow files which have no filename extension. */
|
|
47401
|
+
const CALLER_FILE_NAMES = new Set(['Makefile', 'Dockerfile', 'Jenkinsfile', 'Procfile']);
|
|
47402
|
+
/**
|
|
47403
|
+
* Finds external project callers conservatively; it never rewrites their shell expressions.
|
|
47404
|
+
* @private migration safety check for the Coder initializer
|
|
47405
|
+
*/
|
|
47406
|
+
async function findLegacyCoderCheckCallers(projectPath, legacyNames) {
|
|
47407
|
+
const callers = Object.fromEntries(legacyNames.map((name) => [name, []]));
|
|
47408
|
+
if (legacyNames.length === 0)
|
|
47409
|
+
return callers;
|
|
47410
|
+
/** Scans maintained text files without following symlinks or inspecting runtime state. */
|
|
47411
|
+
async function visit(relativeDirectory) {
|
|
47412
|
+
let entries;
|
|
47413
|
+
try {
|
|
47414
|
+
entries = await readdir(join(projectPath, relativeDirectory), { withFileTypes: true });
|
|
47415
|
+
}
|
|
47416
|
+
catch (_a) {
|
|
47417
|
+
for (const legacyName of legacyNames)
|
|
47418
|
+
callers[legacyName].push(`${relativeDirectory} (unreadable directory; review manually)`);
|
|
47419
|
+
return;
|
|
47420
|
+
}
|
|
47421
|
+
for (const entry of entries) {
|
|
47422
|
+
const relativePath = relativeDirectory ? `${relativeDirectory}/${entry.name}` : entry.name;
|
|
47423
|
+
if (entry.isSymbolicLink()) {
|
|
47424
|
+
if (!IGNORED_CALLER_DIRECTORIES.has(entry.name)) {
|
|
47425
|
+
for (const legacyName of legacyNames)
|
|
47426
|
+
callers[legacyName].push(`${relativePath} (symbolic link; review manually)`);
|
|
47427
|
+
}
|
|
47428
|
+
continue;
|
|
47429
|
+
}
|
|
47430
|
+
if (entry.isDirectory()) {
|
|
47431
|
+
if (!IGNORED_CALLER_DIRECTORIES.has(entry.name) && !IGNORED_CALLER_HISTORY_PATHS.has(relativePath))
|
|
47432
|
+
await visit(relativePath);
|
|
47433
|
+
}
|
|
47434
|
+
else if (entry.isFile() && (CALLER_FILE_PATTERN.test(entry.name) || CALLER_FILE_NAMES.has(entry.name))) {
|
|
47435
|
+
try {
|
|
47436
|
+
let content = await readFile(join(projectPath, relativePath), 'utf-8');
|
|
47437
|
+
if (relativePath === 'package.json') {
|
|
47438
|
+
// Script callers are already handled by the merge. Other project-owned metadata may also
|
|
47439
|
+
// reference a script, so it must be included when deciding whether removal is safe.
|
|
47440
|
+
const packageMetadata = JSON.parse(content);
|
|
47441
|
+
delete packageMetadata.scripts;
|
|
47442
|
+
content = JSON.stringify(packageMetadata);
|
|
47443
|
+
}
|
|
47444
|
+
for (const legacyName of legacyNames) {
|
|
47445
|
+
if (content.includes(legacyName))
|
|
47446
|
+
callers[legacyName].push(relativePath === 'package.json' ? 'package.json (outside scripts)' : relativePath);
|
|
47447
|
+
}
|
|
47448
|
+
}
|
|
47449
|
+
catch (_b) {
|
|
47450
|
+
// An unreadable file cannot prove that deletion is safe. Keep the entry and explain why.
|
|
47451
|
+
for (const legacyName of legacyNames)
|
|
47452
|
+
callers[legacyName].push(`${relativePath} (unreadable; review manually)`);
|
|
47453
|
+
}
|
|
47454
|
+
}
|
|
47455
|
+
}
|
|
47456
|
+
}
|
|
47457
|
+
await visit('');
|
|
47458
|
+
return callers;
|
|
47459
|
+
}
|
|
47460
|
+
|
|
46886
47461
|
/**
|
|
46887
47462
|
* Relative path to `package.json` in the initialized project.
|
|
46888
47463
|
*/
|
|
@@ -46890,17 +47465,30 @@ const PACKAGE_JSON_FILE_PATH = 'package.json';
|
|
|
46890
47465
|
/**
|
|
46891
47466
|
* Ensures `package.json` contains the standalone Promptbook coder helper scripts.
|
|
46892
47467
|
*
|
|
46893
|
-
*
|
|
47468
|
+
* Project definitions are preserved; missing scripts and narrowly recognized generated migrations are applied.
|
|
46894
47469
|
*
|
|
46895
47470
|
* @private function of `initializeCoderProjectConfiguration`
|
|
46896
47471
|
*/
|
|
46897
47472
|
async function ensureCoderPackageJsonFile(projectPath) {
|
|
46898
|
-
|
|
47473
|
+
let preparation;
|
|
47474
|
+
const mergedFile = await mergeStringRecordJsonFile({
|
|
46899
47475
|
projectPath,
|
|
46900
47476
|
relativeFilePath: PACKAGE_JSON_FILE_PATH,
|
|
46901
47477
|
fieldPath: 'scripts',
|
|
46902
47478
|
nextEntries: getDefaultCoderPackageJsonScripts(),
|
|
47479
|
+
transformExistingEntries: async (entries) => {
|
|
47480
|
+
const legacyNames = Object.keys(entries).filter((name) => name === 'test-for-ptbk-coder' || name === 'check-for-ptbk-coder');
|
|
47481
|
+
const externalCallers = await findLegacyCoderCheckCallers(projectPath, legacyNames);
|
|
47482
|
+
preparation = prepareCoderPackageJsonScripts(entries, externalCallers);
|
|
47483
|
+
return preparation.scripts;
|
|
47484
|
+
},
|
|
46903
47485
|
});
|
|
47486
|
+
return {
|
|
47487
|
+
...mergedFile,
|
|
47488
|
+
checkScriptSummary: preparation.checkScriptSummary,
|
|
47489
|
+
migrationInstructions: preparation.migrationInstructions,
|
|
47490
|
+
isCheckConfigured: preparation.isCheckConfigured,
|
|
47491
|
+
};
|
|
46904
47492
|
}
|
|
46905
47493
|
// Note: [🟡] Code for coder init package.json bootstrapping [ensureCoderPackageJsonFile](src/cli/cli-commands/coder/ensureCoderPackageJsonFile.ts) should never be published outside of `@promptbook/cli`
|
|
46906
47494
|
|
|
@@ -47194,9 +47782,9 @@ const PROMPTS_README_TEMPLATE = spaceTrim$1(`
|
|
|
47194
47782
|
|
|
47195
47783
|
Runner-written completion lines may attribute implementation to a harness and model, include
|
|
47196
47784
|
reasoning/authentication labels, attempts or interrupted/continued history, and report implementation,
|
|
47197
|
-
|
|
47198
|
-
or a frozen list of supported models. A completed status alone does not prove
|
|
47199
|
-
execute
|
|
47785
|
+
checking, fixing, or total cost/time information. Those are observed run metadata, not instructions, budgets,
|
|
47786
|
+
or a frozen list of supported models. A completed status alone does not prove checks ran: direct runs only
|
|
47787
|
+
execute the project check command when configured. Preserve actual measurements and record unknown
|
|
47200
47788
|
results or checks that were not run honestly. Manual users must not invent cost/time figures, copy another
|
|
47201
47789
|
run's attribution, or mark unverified work as verified. The textual metadata rows above demonstrate syntax
|
|
47202
47790
|
only; use them only when the described events actually happened.
|
|
@@ -47247,9 +47835,9 @@ const PROMPTS_README_TEMPLATE = spaceTrim$1(`
|
|
|
47247
47835
|
| ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
47248
47836
|
| \`ptbk init\` / \`ptbk coder init\` | Initializes missing Git, then creates missing configuration, local Books, this guide, and fresh-directory boilerplates; preserves project-owned content. \`--no-questions\` skips installation questions/checks. |
|
|
47249
47837
|
| \`ptbk coder add "Describe the reviewed change"\` | Creates one numbered, tagged pending PRD. Accepts a description argument, stdin, or interactive input; \`--priority\` and \`--template\` are available. It does not discuss or implement the task. Review the generated requirements before running. |
|
|
47250
|
-
| \`ptbk coder plan --harness openai-codex\` | Interactive planning with the local
|
|
47838
|
+
| \`ptbk coder plan --harness openai-codex\` | Interactive planning with the local Developer. Review proposals; \`/save\` writes pending PRDs, \`/draft\` writes not-ready drafts, \`/discard\` drops proposals, \`/exit\` ends. It changes PRD Markdown only and never implements or starts the queue. Currently this planning command supports the Codex harness in a compatible interactive terminal. |
|
|
47251
47839
|
| \`ptbk coder list\` | Displays fully authored pending tasks grouped by descending priority without execution or file changes. Optional harness/model/agent and priority filters narrow the list. |
|
|
47252
|
-
| \`ptbk coder run --harness openai-codex --limit 1 --no-commit --no-auto --
|
|
47840
|
+
| \`ptbk coder run --harness openai-codex --limit 1 --no-commit --no-auto --check "npm run check"\` | Confirms and implements one selected task, then runs the specified project check. Replace the check command as needed. Without \`--limit\`, execution proceeds through the eligible queue; without \`--no-commit\`, run stages and commits its changes. |
|
|
47253
47841
|
| \`ptbk coder verify\` | Human review helper: shows completion claims, offers archival or a repair section, and can also ask about pending tasks. It does not run acceptance tests itself. Archival moves the whole file to \`done/\`, so inspect every section before agreeing. There is no separate archive command. |
|
|
47254
47842
|
| \`ptbk coder find-unwritten\` | Lists pending sections still containing authoring placeholders; not-ready drafts are not included. |
|
|
47255
47843
|
| \`ptbk coder generate-boilerplates\` | Adds not-ready starter sections using reusable templates; author and review them before making them pending. |
|
|
@@ -47261,11 +47849,18 @@ const PROMPTS_README_TEMPLATE = spaceTrim$1(`
|
|
|
47261
47849
|
pulling require the corresponding explicit options. Consult \`ptbk coder --help\` and the relevant subcommand's
|
|
47262
47850
|
\`--help\` for the installed version's full options.
|
|
47263
47851
|
|
|
47264
|
-
The initialized \`npm run coder:run\` script
|
|
47265
|
-
|
|
47266
|
-
|
|
47267
|
-
|
|
47268
|
-
|
|
47852
|
+
The initialized \`npm run coder:run\` script selects the Codex harness and uses
|
|
47853
|
+
\`--check "npm run check" --check-before yes-and-fix\`. Developer, the current project directory, and its
|
|
47854
|
+
\`AGENTS.md\` are shared CLI defaults. A **check** covers the project's chosen tests, linting, typechecking,
|
|
47855
|
+
builds, generated-code consistency, and other validation. Tests remain one kind of check.
|
|
47856
|
+
Init preserves an existing \`scripts.check\` exactly, or composes applicable existing validation scripts and
|
|
47857
|
+
reports the selected scope. If none are usable, it creates a failing setup placeholder: configure real
|
|
47858
|
+
validation before running Coder. Missing checks or setup placeholders stop with setup guidance, without model repairs.
|
|
47859
|
+
Direct \`ptbk coder run\` defaults to \`--check-before no\`; checks after prompts remain opt-in. Enabled
|
|
47860
|
+
preflight without an explicit command uses \`npm run check\`, including during repair verification.
|
|
47861
|
+
Replace retired \`--test\` / \`--test-before\` with \`--check\` / \`--check-before\`. Init migrates recognized
|
|
47862
|
+
generated scripts and preserves custom legacy validation in \`check\`. Conflicting definitions or custom callers
|
|
47863
|
+
are preserved with manual migration instructions; review them before removing a legacy script.
|
|
47269
47864
|
|
|
47270
47865
|
### Book agent, harness, and model
|
|
47271
47866
|
|
|
@@ -47277,9 +47872,20 @@ const PROMPTS_README_TEMPLATE = spaceTrim$1(`
|
|
|
47277
47872
|
Init creates local Developer and Planner Books in \`agents/developer.book\` and \`agents/planner.book\`, their
|
|
47278
47873
|
Lawyer and Copywriter TEAM advisers, and shared \`agents/.core/adam.book\` instructions. Books can
|
|
47279
47874
|
inherit/import instructions; TEAM entries expose advisers for relevant consultations, not an obligation to
|
|
47280
|
-
invoke everyone. \`run
|
|
47281
|
-
\`--agent agents/
|
|
47282
|
-
|
|
47875
|
+
invoke everyone. \`run\`, \`server\` and \`plan\` default to Developer.
|
|
47876
|
+
\`--agent ./agents/planner.book\` selects Planner explicitly; another Book path also works. \`list\` has no
|
|
47877
|
+
default Book filter. Every Book used in \`plan\`, including Developer, still permits planning only.
|
|
47878
|
+
|
|
47879
|
+
Project commands default to the current directory captured when invoked. \`--path\` selects another existing
|
|
47880
|
+
directory, relative to that invocation or absolute; an enclosing Git repository never relocates the project's
|
|
47881
|
+
Books, PRDs or context. Additional context defaults to the actual UTF-8 contents of that project's \`AGENTS.md\`.
|
|
47882
|
+
A missing implicit file warns and continues; an unreadable file fails. \`--context\` replaces the default with
|
|
47883
|
+
inline instructions or a file resolved relative to the selected project; \`--context ""\` disables it.
|
|
47884
|
+
Invalid explicit Books and missing/unreadable explicit context files fail without falling back.
|
|
47885
|
+
Thus \`ptbk coder run --harness openai-codex\` and
|
|
47886
|
+
\`ptbk coder run --harness openai-codex --agent ./agents/developer.book --path . --context ./AGENTS.md\` select
|
|
47887
|
+
the same inputs. New npm scripts rely on these defaults; init still creates missing Books and AGENTS.md even
|
|
47888
|
+
when every script already exists, preserving existing custom scripts, settings and context.
|
|
47283
47889
|
|
|
47284
47890
|
Edit local Books to reflect this project's rules; repeat init preserves customizations and adds missing
|
|
47285
47891
|
defaults/helper references. An invalid explicit Book selection fails rather than silently changing roles.
|
|
@@ -47350,7 +47956,7 @@ async function initializeCoderProjectConfiguration(projectPath, onStepCompleted)
|
|
|
47350
47956
|
const adamArtifact = defaultAgentArtifacts.find(({ relativeFilePath }) => relativeFilePath === adamRelativeFilePath);
|
|
47351
47957
|
const { envFileStatus, initializedEnvVariableNames } = await completeStep('.env', ensureCoderEnvFile(projectPath));
|
|
47352
47958
|
const gitignoreFileStatus = await completeStep('.gitignore', ensureCoderGitignoreFile(projectPath));
|
|
47353
|
-
const { status: packageJsonFileStatus, addedEntryKeys: addedPackageJsonScriptNames } = await completeStep('package.json', ensureCoderPackageJsonFile(projectPath));
|
|
47959
|
+
const { status: packageJsonFileStatus, addedEntryKeys: addedPackageJsonScriptNames, checkScriptSummary, migrationInstructions, isCheckConfigured, } = await completeStep('package.json', ensureCoderPackageJsonFile(projectPath));
|
|
47354
47960
|
const vscodeSettingsFileStatus = await completeStep('.vscode/settings.json', ensureCoderVscodeSettingsFile(projectPath));
|
|
47355
47961
|
const referencedArtifactStatuses = [
|
|
47356
47962
|
...defaultAgentArtifacts.filter(({ relativeFilePath }) => relativeFilePath !== adamRelativeFilePath),
|
|
@@ -47371,6 +47977,9 @@ async function initializeCoderProjectConfiguration(projectPath, onStepCompleted)
|
|
|
47371
47977
|
addedPackageJsonScriptNames,
|
|
47372
47978
|
referencedArtifactStatuses,
|
|
47373
47979
|
initializedEnvVariableNames,
|
|
47980
|
+
checkScriptSummary,
|
|
47981
|
+
migrationInstructions,
|
|
47982
|
+
isCheckConfigured,
|
|
47374
47983
|
};
|
|
47375
47984
|
}
|
|
47376
47985
|
// Note: [🟡] Code for coder init project bootstrapping [initializeCoderProjectConfiguration](src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts) should never be published outside of `@promptbook/cli`
|
|
@@ -47382,9 +47991,11 @@ async function initializeCoderProjectConfiguration(projectPath, onStepCompleted)
|
|
|
47382
47991
|
*/
|
|
47383
47992
|
function printInitializationSummary(summary, workspace) {
|
|
47384
47993
|
const isUnresolved = summary.adamAgentFileStatus === 'unresolved' ||
|
|
47994
|
+
!summary.isCheckConfigured ||
|
|
47995
|
+
summary.migrationInstructions.length > 0 ||
|
|
47385
47996
|
summary.referencedArtifactStatuses.some(({ status }) => status === 'unresolved');
|
|
47386
47997
|
console.info(isUnresolved
|
|
47387
|
-
? colors.yellow('Promptbook coder
|
|
47998
|
+
? colors.yellow('Promptbook coder configuration setup: additional setup is required.')
|
|
47388
47999
|
: colors.green('Promptbook coder configuration setup:'));
|
|
47389
48000
|
if (workspace)
|
|
47390
48001
|
console.info(colors.gray(`✔ Git repository: ${workspace.repositoryStatus} (${workspace.repositoryRoot})`));
|
|
@@ -47413,6 +48024,9 @@ function printInitializationSummary(summary, workspace) {
|
|
|
47413
48024
|
else {
|
|
47414
48025
|
printInitializationNote('Required coder env variables are already present.', colors.gray);
|
|
47415
48026
|
}
|
|
48027
|
+
console.info((summary.isCheckConfigured ? colors.cyan : colors.yellow)(summary.checkScriptSummary));
|
|
48028
|
+
for (const instruction of summary.migrationInstructions)
|
|
48029
|
+
console.info(colors.yellow(`! ${instruction}`));
|
|
47416
48030
|
}
|
|
47417
48031
|
/**
|
|
47418
48032
|
* Formats one initialization status into a human-readable label.
|
|
@@ -47494,7 +48108,7 @@ function $initializeCoderInitCommand(program) {
|
|
|
47494
48108
|
- Adds missing local Lawyer and Copywriter TEAM references to Developer and Planner, preserving existing content
|
|
47495
48109
|
- Helpers advise on relevant tasks; declaring TEAM does not run them for every task
|
|
47496
48110
|
- Reports created, augmented, unchanged and unresolved Books; invalid or conflicting files are left untouched
|
|
47497
|
-
-
|
|
48111
|
+
- Missing AGENTS.md is initialized independently of scripts; existing content is preserved
|
|
47498
48112
|
|
|
47499
48113
|
Ensures required coding-agent environment variables in .env:
|
|
47500
48114
|
- CODING_AGENT_GIT_NAME
|
|
@@ -47512,9 +48126,14 @@ function $initializeCoderInitCommand(program) {
|
|
|
47512
48126
|
addQuestionsOption(command);
|
|
47513
48127
|
addWorkspaceRepositoryOptions(command);
|
|
47514
48128
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
48129
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
47515
48130
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
47516
48131
|
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
47517
|
-
const workspace = await $preflightWorkspaceRepository({
|
|
48132
|
+
const workspace = await $preflightWorkspaceRepository({
|
|
48133
|
+
...projectOptions,
|
|
48134
|
+
policy: 'initialize',
|
|
48135
|
+
...questionsOptions,
|
|
48136
|
+
});
|
|
47518
48137
|
const { projectPath } = workspace;
|
|
47519
48138
|
const completedSteps = [`Git repository ${workspace.repositoryStatus}: ${workspace.repositoryRoot}`];
|
|
47520
48139
|
try {
|
|
@@ -47628,6 +48247,11 @@ const CODER_DEFAULT_AGENT_BOOK_PATHS = {
|
|
|
47628
48247
|
developer: CODER_DEVELOPER_AGENT_FILE_PATH,
|
|
47629
48248
|
planner: CODER_PLANNER_AGENT_FILE_PATH,
|
|
47630
48249
|
};
|
|
48250
|
+
/**
|
|
48251
|
+
* Shared persona for optional single-agent execution and authoring; capabilities belong to the command.
|
|
48252
|
+
* @private internal constant of project CLI commands
|
|
48253
|
+
*/
|
|
48254
|
+
const DEFAULT_CODER_AGENT_ROLE = 'developer';
|
|
47631
48255
|
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
47632
48256
|
|
|
47633
48257
|
/**
|
|
@@ -47647,6 +48271,14 @@ function addCoderAgentOption(command, defaultRole) {
|
|
|
47647
48271
|
: 'No default Book filter; omitting --agent includes tasks for all agents';
|
|
47648
48272
|
command.option('--agent <agent-book-path>', `${CODER_AGENT_OPTION_DESCRIPTION}. ${defaultDescription}`);
|
|
47649
48273
|
}
|
|
48274
|
+
/**
|
|
48275
|
+
* Registers the shared optional persona and context for single-agent execution or authoring.
|
|
48276
|
+
* @private internal CLI registration helper
|
|
48277
|
+
*/
|
|
48278
|
+
function addCoderExecutionOptions(command) {
|
|
48279
|
+
addCoderAgentOption(command, DEFAULT_CODER_AGENT_ROLE);
|
|
48280
|
+
addProjectContextOption(command);
|
|
48281
|
+
}
|
|
47650
48282
|
// Note: [🟡] Code for CLI coder agent options should never be published outside of `@promptbook/cli`
|
|
47651
48283
|
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
47652
48284
|
|
|
@@ -47675,9 +48307,13 @@ function $initializeCoderListCommand(program) {
|
|
|
47675
48307
|
addPromptPriorityOptions(command);
|
|
47676
48308
|
addWorkspaceRepositoryOptions(command);
|
|
47677
48309
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
48310
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
47678
48311
|
const { agent, priority, minPriority: minimumPriority, maxPriority: maximumPriority, } = cliOptions;
|
|
47679
48312
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: false });
|
|
47680
|
-
const workspace = await $preflightWorkspaceRepository({
|
|
48313
|
+
const workspace = await $preflightWorkspaceRepository({
|
|
48314
|
+
...projectOptions,
|
|
48315
|
+
policy: 'read-only',
|
|
48316
|
+
});
|
|
47681
48317
|
const resolvedCoderAgentBook = agent === undefined
|
|
47682
48318
|
? undefined
|
|
47683
48319
|
: await (await Promise.resolve().then(function () { return resolveCoderAgent$1; })).resolveCoderAgentBook(agent, workspace.projectPath);
|
|
@@ -47818,12 +48454,17 @@ function $initializeCoderPingCommand(program) {
|
|
|
47818
48454
|
`));
|
|
47819
48455
|
addWorkspaceRepositoryOptions(command);
|
|
47820
48456
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
48457
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
47821
48458
|
const { period: periodValue } = cliOptions;
|
|
47822
48459
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: true });
|
|
47823
48460
|
const questionsOptions = normalizeQuestionsCliOptions(cliOptions);
|
|
47824
48461
|
// Note: The period is validated before the harness installation check, so a mistyped duration fails fast
|
|
47825
48462
|
const periodMs = parseOptionalPeriodDuration('--period', periodValue);
|
|
47826
|
-
const workspace = await $preflightWorkspaceRepository({
|
|
48463
|
+
const workspace = await $preflightWorkspaceRepository({
|
|
48464
|
+
...projectOptions,
|
|
48465
|
+
policy: 'mutate',
|
|
48466
|
+
...questionsOptions,
|
|
48467
|
+
});
|
|
47827
48468
|
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
47828
48469
|
await $ensureCoderHarnessGitignoreRules(workspace.projectPath, runnerOptions.agentName, questionsOptions);
|
|
47829
48470
|
const pingOptions = {
|
|
@@ -47855,10 +48496,10 @@ function $initializeCoderPingCommand(program) {
|
|
|
47855
48496
|
*/
|
|
47856
48497
|
function $initializeCoderPlanCommand(program) {
|
|
47857
48498
|
const command = program.command('plan').description(spaceTrim(`
|
|
47858
|
-
Discuss features with the project's
|
|
48499
|
+
Discuss features with the project's Developer Book and review PRDs before saving them.
|
|
47859
48500
|
|
|
47860
|
-
Run ptbk coder init first. Default Book: agents/
|
|
47861
|
-
independently of --harness and --model. Currently supports openai-codex with restricted tools.
|
|
48501
|
+
Run ptbk coder init first. Default Book: agents/developer.book; --agent overrides the Book,
|
|
48502
|
+
independently of --harness and --model. Use --agent ./agents/planner.book for Planner. Currently supports openai-codex with restricted tools.
|
|
47862
48503
|
Requires an interactive terminal and a Codex version supporting --ignore-user-config and --ignore-rules.
|
|
47863
48504
|
Codex configuration, plugins, hooks and native tools are isolated; --model default uses Codex's built-in default.
|
|
47864
48505
|
/save applies reviewed proposals, /draft saves [-] drafts, /discard drops proposals, /exit ends.
|
|
@@ -47867,11 +48508,12 @@ function $initializeCoderPlanCommand(program) {
|
|
|
47867
48508
|
`));
|
|
47868
48509
|
addPromptRunnerSelectionOptions(command);
|
|
47869
48510
|
addPromptRunnerRuntimeOptions(command);
|
|
47870
|
-
|
|
48511
|
+
addCoderExecutionOptions(command);
|
|
47871
48512
|
addCoderGitSyncOptions(command);
|
|
47872
48513
|
command.option('--template <path>', 'PRD template (defaults to the project-owned prompts/templates/common.md when present)');
|
|
47873
48514
|
addWorkspaceRepositoryOptions(command);
|
|
47874
48515
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
48516
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
47875
48517
|
const { createPlanningTerminal } = await Promise.resolve().then(function () { return createPlanningTerminal$1; });
|
|
47876
48518
|
const { runPlanningSession } = await Promise.resolve().then(function () { return runPlanningSession$1; });
|
|
47877
48519
|
const { resolvePlanningPath } = await Promise.resolve().then(function () { return resolvePlanningPath$1; });
|
|
@@ -47882,12 +48524,18 @@ function $initializeCoderPlanCommand(program) {
|
|
|
47882
48524
|
assertPlanningHarnessSupported(options.agentName);
|
|
47883
48525
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
47884
48526
|
const workspace = await $preflightWorkspaceRepository({
|
|
48527
|
+
...projectOptions,
|
|
47885
48528
|
policy: 'mutate',
|
|
47886
48529
|
isAskingQuestionsEnabled: cliOptions.questions,
|
|
47887
48530
|
});
|
|
47888
48531
|
if (cliOptions.questions === false) {
|
|
47889
48532
|
throw new NotAllowed(spaceTrim('`ptbk coder plan` requires an interactive conversation and review. Run it without `--no-questions` in a terminal.'));
|
|
47890
48533
|
}
|
|
48534
|
+
const { resolveCoderProjectContext } = await Promise.resolve().then(function () { return resolveCoderProjectContext$1; });
|
|
48535
|
+
const projectContext = await resolveCoderProjectContext({
|
|
48536
|
+
...cliOptions,
|
|
48537
|
+
projectPath: workspace.projectPath,
|
|
48538
|
+
});
|
|
47891
48539
|
const terminal = createPlanningTerminal();
|
|
47892
48540
|
try {
|
|
47893
48541
|
const { projectPath } = workspace;
|
|
@@ -47900,6 +48548,8 @@ function $initializeCoderPlanCommand(program) {
|
|
|
47900
48548
|
...options,
|
|
47901
48549
|
projectPath,
|
|
47902
48550
|
agent: cliOptions.agent,
|
|
48551
|
+
context: cliOptions.context,
|
|
48552
|
+
projectContext,
|
|
47903
48553
|
template: cliOptions.template,
|
|
47904
48554
|
preexistingChangedPaths: gitSync.isCommitEnabled
|
|
47905
48555
|
? new Set(Array.from(commitScope.snapshotBeforeOperation.changedFileHashes.keys(), (path) => relative(projectPath, join(workspace.repositoryRoot, path)).replace(/\\/gu, '/')))
|
|
@@ -48089,30 +48739,20 @@ async function $assertSufficientFreeDiskSpace(inspectedPath) {
|
|
|
48089
48739
|
}
|
|
48090
48740
|
// 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`
|
|
48091
48741
|
|
|
48092
|
-
/**
|
|
48093
|
-
* Modes supported by `ptbk coder run --test-before`.
|
|
48094
|
-
*/
|
|
48095
|
-
const TEST_BEFORE_MODE_VALUES = ['no', 'yes-and-fail', 'yes-and-fix'];
|
|
48096
|
-
/**
|
|
48097
|
-
* Default verification command used when a pre-coding mode is enabled without an explicit `--test` command.
|
|
48098
|
-
*/
|
|
48099
|
-
const DEFAULT_CODER_TEST_COMMAND = 'npm test';
|
|
48100
|
-
/**
|
|
48101
|
-
* Checks whether a value is a supported `--test-before` mode.
|
|
48102
|
-
*/
|
|
48103
|
-
function isTestBeforeMode(value) {
|
|
48104
|
-
return TEST_BEFORE_MODE_VALUES.includes(value);
|
|
48105
|
-
}
|
|
48106
|
-
|
|
48107
48742
|
/**
|
|
48108
48743
|
* Validates cross-flag constraints before workspace setup or the run starts.
|
|
48109
48744
|
* @private shared validation for Coder execution commands
|
|
48110
48745
|
*/
|
|
48111
48746
|
function validateCoderRunOptions(options) {
|
|
48112
48747
|
var _a;
|
|
48113
|
-
if (
|
|
48748
|
+
if (options.checkCommand !== undefined && !options.checkCommand.trim()) {
|
|
48114
48749
|
throw new NotAllowed(spaceTrim$1(`
|
|
48115
|
-
|
|
48750
|
+
Option \`--check\` requires a non-empty shell command, for example \`npm run check\`.
|
|
48751
|
+
`));
|
|
48752
|
+
}
|
|
48753
|
+
if (!isCheckBeforeMode((_a = options.checkBefore) !== null && _a !== void 0 ? _a : 'no')) {
|
|
48754
|
+
throw new NotAllowed(spaceTrim$1(`
|
|
48755
|
+
Invalid ${'`--check-before`'} mode: \`${String(options.checkBefore)}\`.
|
|
48116
48756
|
|
|
48117
48757
|
Use one of: \`no\`, \`yes-and-fail\`, \`yes-and-fix\`.
|
|
48118
48758
|
`));
|
|
@@ -48150,9 +48790,9 @@ function validateCoderRunOptions(options) {
|
|
|
48150
48790
|
An isolated task is implemented in a fresh temporary worktree checked out from the last commit, so the uncommitted changes of the interrupted prompt would be left behind instead of being continued.
|
|
48151
48791
|
`));
|
|
48152
48792
|
}
|
|
48153
|
-
if (options.gitChanges === 'continue' && options.
|
|
48793
|
+
if (options.gitChanges === 'continue' && options.checkBefore === 'yes-and-fix') {
|
|
48154
48794
|
throw new NotAllowed(spaceTrim$1(`
|
|
48155
|
-
Flag \`--git-changes continue\` cannot be combined with \`--
|
|
48795
|
+
Flag \`--git-changes continue\` cannot be combined with \`--check-before yes-and-fix\`.
|
|
48156
48796
|
|
|
48157
48797
|
An interrupted prompt already has changes in progress, so there is no unmodified project state for pre-coding verification to repair.
|
|
48158
48798
|
`));
|
|
@@ -48199,9 +48839,9 @@ const NODE_MODULES_DIRECTORY_NAME = 'node_modules';
|
|
|
48199
48839
|
*
|
|
48200
48840
|
* @private internal utility of `promptbookCli`
|
|
48201
48841
|
*/
|
|
48202
|
-
async function $resolvePromptbookCliInstallations() {
|
|
48842
|
+
async function $resolvePromptbookCliInstallations(projectPath = process.cwd()) {
|
|
48203
48843
|
const [localInstallations, globalInstallations] = await Promise.all([
|
|
48204
|
-
$resolveLocalPromptbookCliInstallations(),
|
|
48844
|
+
$resolveLocalPromptbookCliInstallations(projectPath),
|
|
48205
48845
|
$resolveGlobalPromptbookCliInstallations(),
|
|
48206
48846
|
]);
|
|
48207
48847
|
return [...localInstallations, ...globalInstallations];
|
|
@@ -48209,8 +48849,8 @@ async function $resolvePromptbookCliInstallations() {
|
|
|
48209
48849
|
/**
|
|
48210
48850
|
* Finds the closest ancestor `package.json` which directly declares a Promptbook CLI package.
|
|
48211
48851
|
*/
|
|
48212
|
-
async function $resolveLocalPromptbookCliInstallations() {
|
|
48213
|
-
let candidateProjectPath = resolve(
|
|
48852
|
+
async function $resolveLocalPromptbookCliInstallations(projectPath) {
|
|
48853
|
+
let candidateProjectPath = resolve(projectPath);
|
|
48214
48854
|
let isFileSystemRootReached = false;
|
|
48215
48855
|
while (!isFileSystemRootReached) {
|
|
48216
48856
|
const projectPackageJson = await $readJsonObject(join(candidateProjectPath, PACKAGE_JSON_FILENAME));
|
|
@@ -48366,8 +49006,8 @@ function isDefined(value) {
|
|
|
48366
49006
|
*
|
|
48367
49007
|
* @private internal utility of `promptbookCli`
|
|
48368
49008
|
*/
|
|
48369
|
-
async function $checkPromptbookCliInstallations() {
|
|
48370
|
-
const installations = await $resolvePromptbookCliInstallations();
|
|
49009
|
+
async function $checkPromptbookCliInstallations(projectPath = process.cwd()) {
|
|
49010
|
+
const installations = await $resolvePromptbookCliInstallations(projectPath);
|
|
48371
49011
|
if (installations.length === 0) {
|
|
48372
49012
|
return [];
|
|
48373
49013
|
}
|
|
@@ -48422,10 +49062,10 @@ function buildPromptbookCliInstallCommand(installation) {
|
|
|
48422
49062
|
* @returns `true` when the package update succeeds, `false` when it fails
|
|
48423
49063
|
* @private internal utility of `promptbookCli`
|
|
48424
49064
|
*/
|
|
48425
|
-
async function $updatePromptbookCliInstallation(status) {
|
|
49065
|
+
async function $updatePromptbookCliInstallation(status, projectPath = process.cwd()) {
|
|
48426
49066
|
const { npmPackageName, installationLocation } = status.installation;
|
|
48427
49067
|
const installCommand = buildPromptbookCliInstallCommand(status.installation);
|
|
48428
|
-
const updateWorkingDirectory = installationLocation === 'global' ?
|
|
49068
|
+
const updateWorkingDirectory = installationLocation === 'global' ? projectPath : status.installation.projectPath;
|
|
48429
49069
|
console.info(colors.cyan(`Updating Promptbook CLI package \`${npmPackageName}\` with \`${installCommand}\`...`));
|
|
48430
49070
|
try {
|
|
48431
49071
|
await $execCommand({
|
|
@@ -48495,7 +49135,7 @@ function formatPromptbookCliInstallationLocation(installationLocation) {
|
|
|
48495
49135
|
* @returns `true` when at least one installation was updated and the current coder run should stop
|
|
48496
49136
|
* @private internal utility of `promptbookCli`
|
|
48497
49137
|
*/
|
|
48498
|
-
async function $ensurePromptbookCliInstallations(questionsOptions) {
|
|
49138
|
+
async function $ensurePromptbookCliInstallations(questionsOptions, projectPath = process.cwd()) {
|
|
48499
49139
|
if (!questionsOptions.isAskingQuestionsEnabled) {
|
|
48500
49140
|
// Note: `--no-questions` forbids asking for the approval, so the registry checks would be useless
|
|
48501
49141
|
return false;
|
|
@@ -48504,7 +49144,7 @@ async function $ensurePromptbookCliInstallations(questionsOptions) {
|
|
|
48504
49144
|
// Note: Non-interactive runs cannot approve an update and should not wait for registry checks
|
|
48505
49145
|
return false;
|
|
48506
49146
|
}
|
|
48507
|
-
const statuses = await $checkPromptbookCliInstallations();
|
|
49147
|
+
const statuses = await $checkPromptbookCliInstallations(projectPath);
|
|
48508
49148
|
const outdatedStatuses = statuses.filter(({ installationState }) => installationState === 'outdated');
|
|
48509
49149
|
if (outdatedStatuses.length === 0) {
|
|
48510
49150
|
reportPromptbookCliInstallationStatuses(statuses);
|
|
@@ -48518,7 +49158,7 @@ async function $ensurePromptbookCliInstallations(questionsOptions) {
|
|
|
48518
49158
|
}
|
|
48519
49159
|
const updateResults = [];
|
|
48520
49160
|
for (const status of outdatedStatuses) {
|
|
48521
|
-
updateResults.push(await $updatePromptbookCliInstallation(status));
|
|
49161
|
+
updateResults.push(await $updatePromptbookCliInstallation(status, projectPath));
|
|
48522
49162
|
}
|
|
48523
49163
|
const isAnyInstallationUpdated = updateResults.some(Boolean);
|
|
48524
49164
|
const isEveryInstallationUpdated = updateResults.every(Boolean);
|
|
@@ -48563,6 +49203,89 @@ function reportManualPromptbookCliUpdateCommands(outdatedStatuses) {
|
|
|
48563
49203
|
}
|
|
48564
49204
|
// Note: [🟡] Code for Promptbook CLI installation orchestration [$ensurePromptbookCliInstallations](src/cli/cli-commands/common/promptbook-cli/$ensurePromptbookCliInstallations.ts) should never be published outside of `@promptbook/cli`
|
|
48565
49205
|
|
|
49206
|
+
/** Standalone shell composition tokens remain operators when a command is supplied as several arguments. */
|
|
49207
|
+
const SHELL_COMPOSITION_TOKENS = new Set([
|
|
49208
|
+
'&&',
|
|
49209
|
+
'||',
|
|
49210
|
+
'|',
|
|
49211
|
+
'|&',
|
|
49212
|
+
'&',
|
|
49213
|
+
';',
|
|
49214
|
+
'(',
|
|
49215
|
+
')',
|
|
49216
|
+
'>',
|
|
49217
|
+
'>>',
|
|
49218
|
+
'<',
|
|
49219
|
+
'2>',
|
|
49220
|
+
'2>>',
|
|
49221
|
+
'2>&1',
|
|
49222
|
+
]);
|
|
49223
|
+
/**
|
|
49224
|
+
* Retired aggregate option spellings and their canonical replacements, used only for migration diagnostics.
|
|
49225
|
+
* @private shared CLI migration definitions for Coder execution
|
|
49226
|
+
*/
|
|
49227
|
+
const LEGACY_CODER_CHECK_OPTIONS = [
|
|
49228
|
+
['--test', '--check'],
|
|
49229
|
+
['--test-before', '--check-before'],
|
|
49230
|
+
];
|
|
49231
|
+
/**
|
|
49232
|
+
* Registers the shared project check command and rejects retired aggregate-test spellings.
|
|
49233
|
+
* @private shared CLI registration for Coder execution
|
|
49234
|
+
*/
|
|
49235
|
+
function addCoderCheckOptions(command, isCheckBeforeSupported) {
|
|
49236
|
+
command.option('--check <check-command...>', 'Run project checks after each prompt; quote the full command when it contains flags or shell composition');
|
|
49237
|
+
if (isCheckBeforeSupported) {
|
|
49238
|
+
command.addOption(new Option('--check-before <mode>', `Check before coding: ${CHECK_BEFORE_MODE_VALUES.join(', ')} (defaults to no; uses npm run check when --check is omitted)`)
|
|
49239
|
+
.choices([...CHECK_BEFORE_MODE_VALUES])
|
|
49240
|
+
.default('no'));
|
|
49241
|
+
}
|
|
49242
|
+
// These diagnostic-only options never forward a value or start execution.
|
|
49243
|
+
for (const [legacyFlag, replacementFlag] of LEGACY_CODER_CHECK_OPTIONS) {
|
|
49244
|
+
command.addOption(new Option(`${legacyFlag} [value...]`).hideHelp());
|
|
49245
|
+
command.on(`option:${legacyFlag.slice(2)}`, () => {
|
|
49246
|
+
command.error(formatLegacyCoderCheckOptionError(legacyFlag, replacementFlag));
|
|
49247
|
+
});
|
|
49248
|
+
}
|
|
49249
|
+
}
|
|
49250
|
+
/**
|
|
49251
|
+
* Builds the same actionable migration diagnostic for registered and direct-script entrypoints.
|
|
49252
|
+
* @private shared CLI diagnostic for Coder execution
|
|
49253
|
+
*/
|
|
49254
|
+
function formatLegacyCoderCheckOptionError(legacyFlag, replacementFlag) {
|
|
49255
|
+
return `Aggregate verification option \`${legacyFlag}\` was renamed to \`${replacementFlag}\`. Update your command and package.json scripts.`;
|
|
49256
|
+
}
|
|
49257
|
+
/**
|
|
49258
|
+
* Normalizes shell command tokens without parsing a quoted command again or losing spaced argument boundaries.
|
|
49259
|
+
* @private shared command normalization for Coder execution
|
|
49260
|
+
*/
|
|
49261
|
+
function normalizeCheckCommandOption(value) {
|
|
49262
|
+
var _a, _b;
|
|
49263
|
+
if (value === undefined)
|
|
49264
|
+
return undefined;
|
|
49265
|
+
const parts = typeof value === 'string' ? [value] : value;
|
|
49266
|
+
const firstPart = (_b = (_a = parts[0]) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : '';
|
|
49267
|
+
for (const [legacyFlag, replacementFlag] of LEGACY_CODER_CHECK_OPTIONS) {
|
|
49268
|
+
if (firstPart === legacyFlag || firstPart.startsWith(`${legacyFlag}=`)) {
|
|
49269
|
+
throw new NotAllowed(formatLegacyCoderCheckOptionError(legacyFlag, replacementFlag));
|
|
49270
|
+
}
|
|
49271
|
+
}
|
|
49272
|
+
const command = parts.length === 1
|
|
49273
|
+
? parts[0].trim()
|
|
49274
|
+
: parts
|
|
49275
|
+
.map((part) => !SHELL_COMPOSITION_TOKENS.has(part) && (!part || /[\s'"\\$`;&|<>()*?]/u.test(part))
|
|
49276
|
+
? quoteBashArgument(part)
|
|
49277
|
+
: part)
|
|
49278
|
+
.join(' ')
|
|
49279
|
+
.trim();
|
|
49280
|
+
if (!command || !firstPart || firstPart.startsWith('-')) {
|
|
49281
|
+
throw new NotAllowed(spaceTrim$1(`
|
|
49282
|
+
Option \`--check\` requires a non-empty shell command, for example \`--check "npm run check"\`.
|
|
49283
|
+
`));
|
|
49284
|
+
}
|
|
49285
|
+
return command;
|
|
49286
|
+
}
|
|
49287
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
49288
|
+
|
|
48566
49289
|
/**
|
|
48567
49290
|
* Prints why a coder run has ended to the terminal.
|
|
48568
49291
|
*
|
|
@@ -48609,20 +49332,16 @@ function $initializeCoderRunCommand(program) {
|
|
|
48609
49332
|
- Offers to add missing project-local ignore rules for the selected harness
|
|
48610
49333
|
- In interactive mode, checks local and global Promptbook CLI installations and offers to update them
|
|
48611
49334
|
- Supports GPG signing of commits
|
|
48612
|
-
- Optional pre-coding
|
|
48613
|
-
- Optional post-prompt
|
|
49335
|
+
- Optional pre-coding check run that can stop or repair pre-existing failures
|
|
49336
|
+
- Optional post-prompt checks with check-feedback retries
|
|
48614
49337
|
- Progress tracking and interactive P/S/X terminal controls; O changes only the dashboard output view
|
|
48615
49338
|
- Dry-run mode to preview prompts
|
|
48616
49339
|
`));
|
|
48617
49340
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
48618
49341
|
addPromptRunnerSelectionOptions(command);
|
|
48619
49342
|
addQuestionsOption(command);
|
|
48620
|
-
|
|
48621
|
-
command
|
|
48622
|
-
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
48623
|
-
command.addOption(new Option('--test-before <mode>', `Run tests before coding: ${TEST_BEFORE_MODE_VALUES.join(', ')} (defaults to no; uses npm test when --test is omitted)`)
|
|
48624
|
-
.choices([...TEST_BEFORE_MODE_VALUES])
|
|
48625
|
-
.default('no'));
|
|
49343
|
+
addCoderExecutionOptions(command);
|
|
49344
|
+
addCoderCheckOptions(command, true);
|
|
48626
49345
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
48627
49346
|
addPromptRunnerExecutionOptions(command);
|
|
48628
49347
|
command.option('--isolate', spaceTrim$1(`
|
|
@@ -48651,9 +49370,9 @@ function $initializeCoderRunCommand(program) {
|
|
|
48651
49370
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
48652
49371
|
addWorkspaceRepositoryOptions(command);
|
|
48653
49372
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
48654
|
-
const
|
|
48655
|
-
const
|
|
48656
|
-
const
|
|
49373
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
49374
|
+
const { dryRun, agent, context, check, checkBefore, preserveLogs, isolate: isIsolated, priority, minPriority: minimumPriority, maxPriority: maximumPriority, limit, waitAfterPrompt: waitAfterPromptValue, waitBetweenPrompts: waitBetweenPromptsValue, waitAfterError: waitAfterErrorValue, auto, autoMigrate, allowDestructiveAutoMigrate, } = cliOptions;
|
|
49375
|
+
const checkCommand = resolveCoderCheckCommand(normalizeCheckCommandOption(check), checkBefore);
|
|
48657
49376
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
48658
49377
|
isAgentRequired: !dryRun,
|
|
48659
49378
|
});
|
|
@@ -48682,8 +49401,8 @@ function $initializeCoderRunCommand(program) {
|
|
|
48682
49401
|
model: runnerOptions.model,
|
|
48683
49402
|
agent,
|
|
48684
49403
|
context,
|
|
48685
|
-
|
|
48686
|
-
|
|
49404
|
+
checkCommand,
|
|
49405
|
+
checkBefore,
|
|
48687
49406
|
preserveLogs,
|
|
48688
49407
|
isIsolated,
|
|
48689
49408
|
noUi: runnerOptions.noUi,
|
|
@@ -48702,16 +49421,20 @@ function $initializeCoderRunCommand(program) {
|
|
|
48702
49421
|
};
|
|
48703
49422
|
validateCoderRunOptions(runOptions);
|
|
48704
49423
|
const workspace = await $preflightWorkspaceRepository({
|
|
49424
|
+
...projectOptions,
|
|
48705
49425
|
policy: dryRun ? 'read-only' : 'mutate',
|
|
48706
49426
|
...questionsOptions,
|
|
48707
49427
|
});
|
|
49428
|
+
const { resolveCoderProjectContext } = await Promise.resolve().then(function () { return resolveCoderProjectContext$1; });
|
|
49429
|
+
const projectContext = await resolveCoderProjectContext({
|
|
49430
|
+
projectPath: workspace.projectPath,
|
|
49431
|
+
agent,
|
|
49432
|
+
context,
|
|
49433
|
+
});
|
|
48708
49434
|
if (!dryRun) {
|
|
48709
|
-
// Reject missing or unreadable Books before offering installations or project configuration writes.
|
|
48710
|
-
const { resolveCoderAgentBook } = await Promise.resolve().then(function () { return resolveCoderAgent$1; });
|
|
48711
|
-
await resolveCoderAgentBook(agent, workspace.projectPath, { defaultRole: 'developer' });
|
|
48712
49435
|
// Check disk space before installations and repository writes; previews require no setup.
|
|
48713
49436
|
await $assertSufficientFreeDiskSpace(workspace.projectPath);
|
|
48714
|
-
if (await $ensurePromptbookCliInstallations(questionsOptions)) {
|
|
49437
|
+
if (await $ensurePromptbookCliInstallations(questionsOptions, workspace.projectPath)) {
|
|
48715
49438
|
return process.exit(0);
|
|
48716
49439
|
}
|
|
48717
49440
|
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
@@ -48720,8 +49443,7 @@ function $initializeCoderRunCommand(program) {
|
|
|
48720
49443
|
// Note: Import the function dynamically to avoid loading heavy dependencies until needed
|
|
48721
49444
|
const { runCodexPrompts } = await Promise.resolve().then(function () { return runCodexPrompts$1; });
|
|
48722
49445
|
try {
|
|
48723
|
-
|
|
48724
|
-
await runCodexPrompts({ ...runOptions, workspace });
|
|
49446
|
+
await runCodexPrompts({ ...runOptions, workspace, projectContext });
|
|
48725
49447
|
}
|
|
48726
49448
|
catch (error) {
|
|
48727
49449
|
assertsError(error);
|
|
@@ -48731,23 +49453,6 @@ function $initializeCoderRunCommand(program) {
|
|
|
48731
49453
|
return process.exit(0);
|
|
48732
49454
|
}));
|
|
48733
49455
|
}
|
|
48734
|
-
/**
|
|
48735
|
-
* Joins one Commander option that may be parsed either as a single string or a variadic token array.
|
|
48736
|
-
*
|
|
48737
|
-
* @private internal utility of `coder run` command
|
|
48738
|
-
*/
|
|
48739
|
-
function normalizeCommandOptionValue$1(value) {
|
|
48740
|
-
if (value === undefined) {
|
|
48741
|
-
return undefined;
|
|
48742
|
-
}
|
|
48743
|
-
const parts = Array.isArray(value) ? value : [value];
|
|
48744
|
-
const normalizedValue = parts
|
|
48745
|
-
.map((part) => part.trim())
|
|
48746
|
-
.filter(Boolean)
|
|
48747
|
-
.join(' ')
|
|
48748
|
-
.trim();
|
|
48749
|
-
return normalizedValue === '' ? undefined : normalizedValue;
|
|
48750
|
-
}
|
|
48751
49456
|
// Note: [🟡] Code for CLI command [run](src/cli/cli-commands/coder/run.ts) should never be published outside of `@promptbook/cli`
|
|
48752
49457
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
48753
49458
|
|
|
@@ -48793,9 +49498,8 @@ function $initializeCoderServerCommand(program) {
|
|
|
48793
49498
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
48794
49499
|
addPromptRunnerSelectionOptions(command);
|
|
48795
49500
|
addQuestionsOption(command);
|
|
48796
|
-
|
|
48797
|
-
command
|
|
48798
|
-
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
49501
|
+
addCoderExecutionOptions(command);
|
|
49502
|
+
addCoderCheckOptions(command, false);
|
|
48799
49503
|
command.option('--preserve-logs', 'Keep generated temp prompt/log artifacts after successful rounds for debugging and analytics', false);
|
|
48800
49504
|
addPromptRunnerExecutionOptions(command);
|
|
48801
49505
|
addPromptPriorityOptions(command);
|
|
@@ -48817,9 +49521,10 @@ function $initializeCoderServerCommand(program) {
|
|
|
48817
49521
|
command.option('--allow-destructive-auto-migrate', 'Allow auto-migrate even when heuristic SQL safety check flags destructive pending migrations');
|
|
48818
49522
|
addWorkspaceRepositoryOptions(command);
|
|
48819
49523
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
48820
|
-
const
|
|
49524
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
49525
|
+
const { port: rawPort, dryRun, agent, context, check, preserveLogs, priority, minPriority: minimumPriority, maxPriority: maximumPriority, waitAfterPrompt: waitAfterPromptValue, waitBetweenPrompts: waitBetweenPromptsValue, waitAfterError: waitAfterErrorValue, auto, autoMigrate, allowDestructiveAutoMigrate, } = cliOptions;
|
|
48821
49526
|
const port = parseCoderServerPort(rawPort);
|
|
48822
|
-
const
|
|
49527
|
+
const checkCommand = normalizeCheckCommandOption(check);
|
|
48823
49528
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
48824
49529
|
isAgentRequired: !dryRun,
|
|
48825
49530
|
});
|
|
@@ -48843,7 +49548,7 @@ function $initializeCoderServerCommand(program) {
|
|
|
48843
49548
|
model: runnerOptions.model,
|
|
48844
49549
|
agent,
|
|
48845
49550
|
context,
|
|
48846
|
-
|
|
49551
|
+
checkCommand,
|
|
48847
49552
|
preserveLogs,
|
|
48848
49553
|
noUi: runnerOptions.noUi,
|
|
48849
49554
|
thinkingLevel: runnerOptions.thinkingLevel,
|
|
@@ -48860,13 +49565,17 @@ function $initializeCoderServerCommand(program) {
|
|
|
48860
49565
|
};
|
|
48861
49566
|
validateCoderRunOptions(runOptions);
|
|
48862
49567
|
const workspace = await $preflightWorkspaceRepository({
|
|
49568
|
+
...projectOptions,
|
|
48863
49569
|
policy: dryRun ? 'read-only' : 'mutate',
|
|
48864
49570
|
...questionsOptions,
|
|
48865
49571
|
});
|
|
49572
|
+
const { resolveCoderProjectContext } = await Promise.resolve().then(function () { return resolveCoderProjectContext$1; });
|
|
49573
|
+
const projectContext = await resolveCoderProjectContext({
|
|
49574
|
+
projectPath: workspace.projectPath,
|
|
49575
|
+
agent,
|
|
49576
|
+
context,
|
|
49577
|
+
});
|
|
48866
49578
|
if (!dryRun) {
|
|
48867
|
-
// Reject missing or unreadable Books before offering installations or project configuration writes.
|
|
48868
|
-
const { resolveCoderAgentBook } = await Promise.resolve().then(function () { return resolveCoderAgent$1; });
|
|
48869
|
-
await resolveCoderAgentBook(agent, workspace.projectPath, { defaultRole: 'developer' });
|
|
48870
49579
|
// Check disk space before installations and repository writes; previews require no setup.
|
|
48871
49580
|
await $assertSufficientFreeDiskSpace(workspace.projectPath);
|
|
48872
49581
|
await $ensureHarnessInstallations([runnerOptions.agentName], questionsOptions);
|
|
@@ -48875,7 +49584,7 @@ function $initializeCoderServerCommand(program) {
|
|
|
48875
49584
|
// Note: Import dynamically to avoid loading heavy dependencies until needed
|
|
48876
49585
|
const { runCodexPromptsServer } = await Promise.resolve().then(function () { return runCodexPromptsServer$1; });
|
|
48877
49586
|
try {
|
|
48878
|
-
await runCodexPromptsServer({ ...runOptions, workspace });
|
|
49587
|
+
await runCodexPromptsServer({ ...runOptions, workspace, projectContext });
|
|
48879
49588
|
}
|
|
48880
49589
|
catch (error) {
|
|
48881
49590
|
assertsError(error);
|
|
@@ -48901,23 +49610,6 @@ function parseCoderServerPort(rawPort) {
|
|
|
48901
49610
|
}
|
|
48902
49611
|
return port;
|
|
48903
49612
|
}
|
|
48904
|
-
/**
|
|
48905
|
-
* Joins one Commander option that may be parsed either as a single string or a variadic token array.
|
|
48906
|
-
*
|
|
48907
|
-
* @private internal utility of `coder server` command
|
|
48908
|
-
*/
|
|
48909
|
-
function normalizeCommandOptionValue(value) {
|
|
48910
|
-
if (value === undefined) {
|
|
48911
|
-
return undefined;
|
|
48912
|
-
}
|
|
48913
|
-
const parts = Array.isArray(value) ? value : [value];
|
|
48914
|
-
const normalizedValue = parts
|
|
48915
|
-
.map((part) => part.trim())
|
|
48916
|
-
.filter(Boolean)
|
|
48917
|
-
.join(' ')
|
|
48918
|
-
.trim();
|
|
48919
|
-
return normalizedValue === '' ? undefined : normalizedValue;
|
|
48920
|
-
}
|
|
48921
49613
|
// Note: [🟡] Code for CLI command [server](src/cli/cli-commands/coder/server.ts) should never be published outside of `@promptbook/cli`
|
|
48922
49614
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
48923
49615
|
|
|
@@ -48995,9 +49687,11 @@ function $initializeCoderVerifyCommand(program) {
|
|
|
48995
49687
|
addCoderGitSyncOptions(command);
|
|
48996
49688
|
addWorkspaceRepositoryOptions(command);
|
|
48997
49689
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
49690
|
+
const projectOptions = normalizeProjectCliOptions(cliOptions);
|
|
48998
49691
|
const { order, ignore } = cliOptions;
|
|
48999
49692
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
49000
49693
|
const workspace = await $preflightWorkspaceRepository({
|
|
49694
|
+
...projectOptions,
|
|
49001
49695
|
policy: 'mutate',
|
|
49002
49696
|
isAskingQuestionsEnabled: cliOptions.questions,
|
|
49003
49697
|
});
|
|
@@ -49033,7 +49727,7 @@ function collectStringOption(value, previousValues) {
|
|
|
49033
49727
|
* The coder command provides utilities for automated coding:
|
|
49034
49728
|
* - init: Initialize coder configuration in current project
|
|
49035
49729
|
* - add: Add one ready-to-run prompt file to the queue
|
|
49036
|
-
* - plan: Discuss features with
|
|
49730
|
+
* - plan: Discuss features with Developer and author reviewed PRDs
|
|
49037
49731
|
* - generate-boilerplates: Generate prompt boilerplate files
|
|
49038
49732
|
* - find-refactor-candidates: Find files that need refactoring
|
|
49039
49733
|
* - list: List ready prompts in priority order without running them
|
|
@@ -49054,7 +49748,7 @@ function $initializeCoderCommand(program) {
|
|
|
49054
49748
|
Subcommands:
|
|
49055
49749
|
- init: Initialize coder configuration in current project
|
|
49056
49750
|
- add: Add one ready-to-run prompt file to the queue
|
|
49057
|
-
- plan: Discuss features with
|
|
49751
|
+
- plan: Discuss features with Developer and author reviewed PRDs
|
|
49058
49752
|
- generate-boilerplates: Generate prompt boilerplate files
|
|
49059
49753
|
- find-refactor-candidates: Find files that need refactoring
|
|
49060
49754
|
- find-unwritten: List prompt sections that still need to be authored
|
|
@@ -72175,12 +72869,21 @@ async function resolveInlineOrFileText(options) {
|
|
|
72175
72869
|
}
|
|
72176
72870
|
const textPath = resolve(options.currentWorkingDirectory, normalizedTextReference);
|
|
72177
72871
|
const textPathStats = await stat(textPath).catch((error) => {
|
|
72178
|
-
if (error.code === 'ENOENT') {
|
|
72872
|
+
if (error.code === 'ENOENT' || error.code === 'ENOTDIR') {
|
|
72179
72873
|
return undefined;
|
|
72180
72874
|
}
|
|
72181
|
-
|
|
72875
|
+
if (['ENAMETOOLONG', 'EINVAL', 'ERR_INVALID_ARG_VALUE'].includes(error.code || '') && !isContextFileReference(normalizedTextReference)) {
|
|
72876
|
+
return undefined;
|
|
72877
|
+
}
|
|
72878
|
+
throw contextReadError(options, textPath, error);
|
|
72182
72879
|
});
|
|
72183
72880
|
if (!textPathStats) {
|
|
72881
|
+
if (options.isMissingFileAnError && isContextFileReference(normalizedTextReference)) {
|
|
72882
|
+
throw new NotFoundError(spaceTrim(`
|
|
72883
|
+
${options.contextLabel} file \`${textPath}\` does not exist.
|
|
72884
|
+
Correct the file path in \`${options.optionName}\` or pass inline instructions.
|
|
72885
|
+
`));
|
|
72886
|
+
}
|
|
72184
72887
|
return normalizedTextReference;
|
|
72185
72888
|
}
|
|
72186
72889
|
if (!textPathStats.isFile()) {
|
|
@@ -72190,7 +72893,55 @@ async function resolveInlineOrFileText(options) {
|
|
|
72190
72893
|
Pass a file path or inline text in \`${options.optionName}\`.
|
|
72191
72894
|
`));
|
|
72192
72895
|
}
|
|
72193
|
-
return readFile(textPath, 'utf-8')
|
|
72896
|
+
return readFile(textPath, 'utf-8').catch((error) => {
|
|
72897
|
+
throw contextReadError(options, textPath, error);
|
|
72898
|
+
});
|
|
72899
|
+
}
|
|
72900
|
+
/** Distinguishes explicit file spellings from ordinary inline instructions, including native Windows paths. */
|
|
72901
|
+
function isContextFileReference(reference) {
|
|
72902
|
+
return isAbsolute(reference) || /^(?:\.{1,2}[/\\]|[a-z]:[/\\]|\\\\)/iu.test(reference) ||
|
|
72903
|
+
(!/[\r\n]/u.test(reference) && /\.(?:md|markdown|txt|book|json|ya?ml)$/iu.test(reference)) ||
|
|
72904
|
+
(!/\s/u.test(reference) && /[/\\]/u.test(reference) && !/^[a-z]+:\/\//iu.test(reference));
|
|
72905
|
+
}
|
|
72906
|
+
/** Adds the selected path and recovery guidance to filesystem failures. */
|
|
72907
|
+
function contextReadError(options, path, error) {
|
|
72908
|
+
return new NotAllowed(spaceTrim(`
|
|
72909
|
+
Cannot read ${options.contextLabel.toLowerCase()} file \`${path}\`: ${error.message}
|
|
72910
|
+
Check file permissions and the path in \`${options.optionName}\`.
|
|
72911
|
+
`));
|
|
72912
|
+
}
|
|
72913
|
+
|
|
72914
|
+
/**
|
|
72915
|
+
* Resolves project AGENTS.md on omission; explicit text, files and intentional empty values replace it.
|
|
72916
|
+
*/
|
|
72917
|
+
async function resolveCoderContext(contextReference, currentWorkingDirectory) {
|
|
72918
|
+
if (contextReference === undefined) {
|
|
72919
|
+
const contextPath = join(currentWorkingDirectory, AGENTS_FILE_PATH);
|
|
72920
|
+
try {
|
|
72921
|
+
return await readFile(contextPath, 'utf-8');
|
|
72922
|
+
}
|
|
72923
|
+
catch (error) {
|
|
72924
|
+
if (error.code === 'ENOENT') {
|
|
72925
|
+
// A broken symlink is an existing, unreadable default, not an absent optional file.
|
|
72926
|
+
const isMissing = await lstat(contextPath).then(() => false, (failure) => failure.code === 'ENOENT');
|
|
72927
|
+
if (isMissing) {
|
|
72928
|
+
console.warn(`No additional context: \`${contextPath}\` is missing.`);
|
|
72929
|
+
return undefined;
|
|
72930
|
+
}
|
|
72931
|
+
}
|
|
72932
|
+
throw new NotAllowed(spaceTrim(`
|
|
72933
|
+
Cannot read default context file \`${contextPath}\`: ${error instanceof Error ? error.message : String(error)}
|
|
72934
|
+
Check its permissions, or replace it with \`--context\` (an empty value disables additional context).
|
|
72935
|
+
`));
|
|
72936
|
+
}
|
|
72937
|
+
}
|
|
72938
|
+
return resolveInlineOrFileText({
|
|
72939
|
+
textReference: contextReference,
|
|
72940
|
+
currentWorkingDirectory,
|
|
72941
|
+
contextLabel: 'Coding context',
|
|
72942
|
+
optionName: '--context',
|
|
72943
|
+
isMissingFileAnError: true,
|
|
72944
|
+
});
|
|
72194
72945
|
}
|
|
72195
72946
|
|
|
72196
72947
|
/**
|
|
@@ -72269,11 +73020,7 @@ function createAgentChatWorkspacePath(options) {
|
|
|
72269
73020
|
.toLowerCase()
|
|
72270
73021
|
.replace(/[^a-z0-9._-]+/gu, '-')
|
|
72271
73022
|
.replace(/^[._-]+|[._-]+$/gu, '');
|
|
72272
|
-
const sessionName = [
|
|
72273
|
-
safeAgentName || 'agent',
|
|
72274
|
-
Date.now().toString(36),
|
|
72275
|
-
$randomToken(4),
|
|
72276
|
-
].join('-');
|
|
73023
|
+
const sessionName = [safeAgentName || 'agent', Date.now().toString(36), $randomToken(4)].join('-');
|
|
72277
73024
|
return resolvePromptbookTemporaryPath(options.currentWorkingDirectory, AGENT_CHAT_TEMPORARY_DIRECTORY_NAME, AGENT_CHAT_SESSIONS_DIRECTORY_NAME, sessionName);
|
|
72278
73025
|
}
|
|
72279
73026
|
/**
|
|
@@ -72328,7 +73075,7 @@ function createPromptRunnerOptions(options) {
|
|
|
72328
73075
|
return {
|
|
72329
73076
|
dryRun: false,
|
|
72330
73077
|
context: undefined,
|
|
72331
|
-
|
|
73078
|
+
checkCommand: undefined,
|
|
72332
73079
|
preserveLogs: false,
|
|
72333
73080
|
noUi: options.noUi,
|
|
72334
73081
|
thinkingLevel: options.thinkingLevel,
|
|
@@ -72394,12 +73141,7 @@ function normalizeRelativePath(relativePath) {
|
|
|
72394
73141
|
*/
|
|
72395
73142
|
async function runAgentChat(options) {
|
|
72396
73143
|
const currentWorkingDirectory = options.currentWorkingDirectory || process.cwd();
|
|
72397
|
-
const context = await
|
|
72398
|
-
textReference: options.context,
|
|
72399
|
-
currentWorkingDirectory,
|
|
72400
|
-
contextLabel: 'Agent context',
|
|
72401
|
-
optionName: '--context',
|
|
72402
|
-
});
|
|
73144
|
+
const context = await resolveCoderContext(options.context, currentWorkingDirectory);
|
|
72403
73145
|
const workspacePath = createAgentChatWorkspacePath({
|
|
72404
73146
|
currentWorkingDirectory,
|
|
72405
73147
|
agentPath: options.agentPath,
|
|
@@ -72462,12 +73204,7 @@ async function runAgentExec(options) {
|
|
|
72462
73204
|
throw new NotAllowed('Pass a non-empty user message in `--message`.');
|
|
72463
73205
|
}
|
|
72464
73206
|
const currentWorkingDirectory = options.currentWorkingDirectory || process.cwd();
|
|
72465
|
-
const context = await
|
|
72466
|
-
textReference: options.context,
|
|
72467
|
-
currentWorkingDirectory,
|
|
72468
|
-
contextLabel: 'Agent context',
|
|
72469
|
-
optionName: '--context',
|
|
72470
|
-
});
|
|
73207
|
+
const context = await resolveCoderContext(options.context, currentWorkingDirectory);
|
|
72471
73208
|
const result = await executeAgentChatTurn({
|
|
72472
73209
|
...options,
|
|
72473
73210
|
currentWorkingDirectory,
|
|
@@ -72553,13 +73290,13 @@ const AGENT_IDLE_AUTO_PULL_INTERVAL_MS = 30000;
|
|
|
72553
73290
|
* Watches the queued message directory and answers messages one by one.
|
|
72554
73291
|
*/
|
|
72555
73292
|
async function runAgentMessages(options, controls = {}) {
|
|
72556
|
-
var _a, _b;
|
|
73293
|
+
var _a, _b, _c;
|
|
72557
73294
|
validateAgentRunOptions(options);
|
|
72558
73295
|
validateAgentWatchOptions('ptbk agent-folder run-agent', options);
|
|
72559
|
-
const projectPath = process.cwd();
|
|
73296
|
+
const projectPath = (_a = options.projectPath) !== null && _a !== void 0 ? _a : process.cwd();
|
|
72560
73297
|
let autoPullTimestamp = options.autoPull ? Date.now() : undefined;
|
|
72561
73298
|
const shouldContinue = controls.shouldContinue || (() => just(true));
|
|
72562
|
-
const queuePollIntervalMs = (
|
|
73299
|
+
const queuePollIntervalMs = (_b = controls.queuePollIntervalMs) !== null && _b !== void 0 ? _b : AGENT_QUEUE_POLL_INTERVAL_MS;
|
|
72563
73300
|
let isWatchSessionInitialized = false;
|
|
72564
73301
|
let uiHandle;
|
|
72565
73302
|
const messageFailureTracker = new AgentMessageFailureTracker({
|
|
@@ -72576,7 +73313,7 @@ async function runAgentMessages(options, controls = {}) {
|
|
|
72576
73313
|
}
|
|
72577
73314
|
}
|
|
72578
73315
|
const result = await tickAgentMessages(options, { isQuietWhenIdle: true, uiHandle });
|
|
72579
|
-
autoPullTimestamp = (
|
|
73316
|
+
autoPullTimestamp = (_c = result.autoPullTimestamp) !== null && _c !== void 0 ? _c : autoPullTimestamp;
|
|
72580
73317
|
if (result.isMessageProcessed) {
|
|
72581
73318
|
messageFailureTracker.clearMessageFailure(projectPath, result.queuedMessage);
|
|
72582
73319
|
continue;
|
|
@@ -78429,8 +79166,8 @@ async function loadPromptFiles(promptsDir, options = {}) {
|
|
|
78429
79166
|
/**
|
|
78430
79167
|
* Builds a display label using the prompt line number for easier navigation.
|
|
78431
79168
|
*/
|
|
78432
|
-
function buildPromptLabelForDisplay(file, section) {
|
|
78433
|
-
return `${relative(
|
|
79169
|
+
function buildPromptLabelForDisplay(file, section, projectPath = process.cwd()) {
|
|
79170
|
+
return `${relative(projectPath, file.path).replace(/\\/g, '/')}#${section.startLine + 1}`;
|
|
78434
79171
|
}
|
|
78435
79172
|
|
|
78436
79173
|
/**
|
|
@@ -78445,11 +79182,11 @@ function buildPromptSummary(file, section) {
|
|
|
78445
79182
|
/**
|
|
78446
79183
|
* Prints the list of prompts that still need to be written.
|
|
78447
79184
|
*/
|
|
78448
|
-
function printPromptsToBeWritten(files, priorityFilter = {}) {
|
|
79185
|
+
function printPromptsToBeWritten(files, priorityFilter = {}, projectPath) {
|
|
78449
79186
|
const promptsToWrite = listPromptsToBeWritten(files, priorityFilter);
|
|
78450
79187
|
let i = 0;
|
|
78451
79188
|
for (const { file, section } of promptsToWrite) {
|
|
78452
|
-
const label = buildPromptLabelForDisplay(file, section);
|
|
79189
|
+
const label = buildPromptLabelForDisplay(file, section, projectPath);
|
|
78453
79190
|
const summary = buildPromptSummary(file, section);
|
|
78454
79191
|
console.info(` ${++i}) ${label}: ${summary}`);
|
|
78455
79192
|
}
|
|
@@ -78519,7 +79256,7 @@ async function findUnwrittenPrompts(options = {}) {
|
|
|
78519
79256
|
}
|
|
78520
79257
|
else {
|
|
78521
79258
|
console.info(colors.yellow(`Found ${unwrittenPrompts.length} prompt(s) that need to be written:`));
|
|
78522
|
-
printPromptsToBeWritten(promptFiles, priorityFilter);
|
|
79259
|
+
printPromptsToBeWritten(promptFiles, priorityFilter, options.projectPath);
|
|
78523
79260
|
}
|
|
78524
79261
|
return unwrittenPrompts.length;
|
|
78525
79262
|
}
|
|
@@ -79363,9 +80100,9 @@ function listRunnablePrompts(files, priorityFilter = {}, promptRunnerIdentity) {
|
|
|
79363
80100
|
/**
|
|
79364
80101
|
* Lists upcoming tasks that are ready to run (no authoring placeholders).
|
|
79365
80102
|
*/
|
|
79366
|
-
function listUpcomingTasks(files, priorityFilter = {}, promptRunnerIdentity) {
|
|
80103
|
+
function listUpcomingTasks(files, priorityFilter = {}, promptRunnerIdentity, projectPath) {
|
|
79367
80104
|
return listRunnablePrompts(files, priorityFilter, promptRunnerIdentity).map(({ file, section }) => ({
|
|
79368
|
-
label: buildPromptLabelForDisplay(file, section),
|
|
80105
|
+
label: buildPromptLabelForDisplay(file, section, projectPath),
|
|
79369
80106
|
summary: buildPromptSummary(file, section),
|
|
79370
80107
|
priority: section.priority,
|
|
79371
80108
|
}));
|
|
@@ -79420,7 +80157,7 @@ async function listCoderPrompts(options = {}) {
|
|
|
79420
80157
|
const promptFiles = await loadPromptFiles(join((_a = options.projectPath) !== null && _a !== void 0 ? _a : process.cwd(), 'prompts'), {
|
|
79421
80158
|
isMissingDirectoryAllowed: true,
|
|
79422
80159
|
});
|
|
79423
|
-
const upcomingTasks = listUpcomingTasks(promptFiles, priorityFilter, options.promptRunnerIdentity);
|
|
80160
|
+
const upcomingTasks = listUpcomingTasks(promptFiles, priorityFilter, options.promptRunnerIdentity, options.projectPath);
|
|
79424
80161
|
printUpcomingTasks(upcomingTasks);
|
|
79425
80162
|
return upcomingTasks.length;
|
|
79426
80163
|
}
|
|
@@ -79800,6 +80537,24 @@ var createPlanningTerminal$1 = /*#__PURE__*/Object.freeze({
|
|
|
79800
80537
|
createPlanningTerminal: createPlanningTerminal
|
|
79801
80538
|
});
|
|
79802
80539
|
|
|
80540
|
+
/**
|
|
80541
|
+
* Resolves single-agent execution/authoring defaults without compiling Books or creating artifacts.
|
|
80542
|
+
* Execution previews use the same identity and routing. Utilities and all-agent discovery resolve
|
|
80543
|
+
* only the project directory and must not call this service to manufacture a primary-agent filter.
|
|
80544
|
+
*/
|
|
80545
|
+
async function resolveCoderProjectContext(options) {
|
|
80546
|
+
const agentBook = await resolveCoderAgentBook(options.agent, options.projectPath, {
|
|
80547
|
+
defaultRole: DEFAULT_CODER_AGENT_ROLE,
|
|
80548
|
+
});
|
|
80549
|
+
const context = await resolveCoderContext(options.context, options.projectPath);
|
|
80550
|
+
return { projectPath: options.projectPath, agentBook, context };
|
|
80551
|
+
}
|
|
80552
|
+
|
|
80553
|
+
var resolveCoderProjectContext$1 = /*#__PURE__*/Object.freeze({
|
|
80554
|
+
__proto__: null,
|
|
80555
|
+
resolveCoderProjectContext: resolveCoderProjectContext
|
|
80556
|
+
});
|
|
80557
|
+
|
|
79803
80558
|
/** Maximum question length accepted by both command and planning tools. */
|
|
79804
80559
|
const MAX_MESSAGE_LENGTH = 32000;
|
|
79805
80560
|
/** Maximum context length accepted by both command and planning tools. */
|
|
@@ -80018,6 +80773,19 @@ class CoderTeamRuntime {
|
|
|
80018
80773
|
}
|
|
80019
80774
|
// Note: [💞] Runtime contract types accompany their implementation.
|
|
80020
80775
|
|
|
80776
|
+
/**
|
|
80777
|
+
* Rebinds an absolute reference inside a project/repository to its worktree copy. Relative references
|
|
80778
|
+
* already resolve against the execution project; explicit references outside that checkout remain explicit.
|
|
80779
|
+
*/
|
|
80780
|
+
function mapProjectReferenceToWorktree(reference, originalProjectPath, worktreeProjectPath) {
|
|
80781
|
+
if (reference === undefined || !isAbsolute(reference.trim()))
|
|
80782
|
+
return reference;
|
|
80783
|
+
const relativePath = relative(originalProjectPath, reference.trim());
|
|
80784
|
+
if (isAbsolute(relativePath) || relativePath === '..' || /^\.\.[/\\]/u.test(relativePath))
|
|
80785
|
+
return reference;
|
|
80786
|
+
return join(worktreeProjectPath, relativePath);
|
|
80787
|
+
}
|
|
80788
|
+
|
|
80021
80789
|
/** Limits apply before JSON parsing, even when a client bypasses the generated command. */
|
|
80022
80790
|
const MAX_REQUEST_BYTES = 131072;
|
|
80023
80791
|
/** Each invocation receives an independent 256-bit bearer credential. */
|
|
@@ -80204,7 +80972,7 @@ function buildBridgeClient(url, token) {
|
|
|
80204
80972
|
* Adds a scoped consultation transport around an existing adapter. Both primary and advisers keep exactly
|
|
80205
80973
|
* that adapter's permissions and authentication. Only the enclosing Coder round owns tests, queues and Git operations.
|
|
80206
80974
|
*/
|
|
80207
|
-
function createCoderTeamPromptRunner(runner, agentBookReference) {
|
|
80975
|
+
function createCoderTeamPromptRunner(runner, agentBookReference, originalProjectPath, originalRepositoryRoot = originalProjectPath) {
|
|
80208
80976
|
var _a;
|
|
80209
80977
|
return {
|
|
80210
80978
|
name: runner.name,
|
|
@@ -80220,8 +80988,11 @@ function createCoderTeamPromptRunner(runner, agentBookReference) {
|
|
|
80220
80988
|
let runtime;
|
|
80221
80989
|
try {
|
|
80222
80990
|
// Resolve against this invocation's actual checkout, including an isolated worktree.
|
|
80223
|
-
const
|
|
80224
|
-
|
|
80991
|
+
const reference = originalProjectPath
|
|
80992
|
+
? mapProjectReferenceToWorktree(agentBookReference, originalRepositoryRoot, resolve(options.projectPath, relative(originalProjectPath, originalRepositoryRoot)))
|
|
80993
|
+
: agentBookReference;
|
|
80994
|
+
const agent = await resolveCoderAgent(reference, options.projectPath, {
|
|
80995
|
+
defaultRole: DEFAULT_CODER_AGENT_ROLE,
|
|
80225
80996
|
isInitializationAllowed: false,
|
|
80226
80997
|
signal: controller.signal,
|
|
80227
80998
|
});
|
|
@@ -81102,11 +81873,12 @@ function writeDurableFile(path, content) {
|
|
|
81102
81873
|
* @private internal utility of `coder plan`
|
|
81103
81874
|
*/
|
|
81104
81875
|
async function runPlanningSession(options, io, harness = runPlanningHarness) {
|
|
81105
|
-
var _a, _b;
|
|
81876
|
+
var _a, _b, _c;
|
|
81106
81877
|
const projectPath = await realpath(options.projectPath);
|
|
81107
81878
|
assertPlanningHarnessSupported(options.agentName);
|
|
81879
|
+
const projectContext = (_a = options.projectContext) !== null && _a !== void 0 ? _a : (await resolveCoderProjectContext({ ...options, projectPath }));
|
|
81108
81880
|
const agent = await resolveCoderAgent(options.agent, projectPath, {
|
|
81109
|
-
defaultRole:
|
|
81881
|
+
defaultRole: DEFAULT_CODER_AGENT_ROLE,
|
|
81110
81882
|
isInitializationAllowed: false,
|
|
81111
81883
|
signal: io.signal,
|
|
81112
81884
|
});
|
|
@@ -81114,9 +81886,9 @@ async function runPlanningSession(options, io, harness = runPlanningHarness) {
|
|
|
81114
81886
|
throw new NotFoundError(spaceTrim('Planning requires `prompts/`. Run `ptbk coder init` first.'));
|
|
81115
81887
|
}
|
|
81116
81888
|
if (!agent)
|
|
81117
|
-
throw new NotFoundError(spaceTrim('
|
|
81889
|
+
throw new NotFoundError(spaceTrim('Primary Book is missing. Run `ptbk coder init`.'));
|
|
81118
81890
|
resolvePlanningPath(projectPath, 'prompts');
|
|
81119
|
-
const templateOption = (
|
|
81891
|
+
const templateOption = (_b = options.template) !== null && _b !== void 0 ? _b : (existsSync(join(projectPath, COMMON_PROMPT_TEMPLATE_FILE_PATH))
|
|
81120
81892
|
? COMMON_PROMPT_TEMPLATE_FILE_PATH
|
|
81121
81893
|
: undefined);
|
|
81122
81894
|
const template = await resolveCoderPromptTemplate({ projectPath, templateOption });
|
|
@@ -81160,7 +81932,10 @@ async function runPlanningSession(options, io, harness = runPlanningHarness) {
|
|
|
81160
81932
|
},
|
|
81161
81933
|
{ role: 'context', content: await readPlanningContext(projectPath, { kind: 'list', path: '.' }) },
|
|
81162
81934
|
];
|
|
81163
|
-
|
|
81935
|
+
if (projectContext.context !== undefined) {
|
|
81936
|
+
history.push({ role: 'context', content: projectContext.context });
|
|
81937
|
+
}
|
|
81938
|
+
for (const path of ['README.md']) {
|
|
81164
81939
|
if (existsSync(join(projectPath, path))) {
|
|
81165
81940
|
history.push({
|
|
81166
81941
|
role: 'context',
|
|
@@ -81177,7 +81952,7 @@ async function runPlanningSession(options, io, harness = runPlanningHarness) {
|
|
|
81177
81952
|
let pending = [];
|
|
81178
81953
|
io.write(`${agent.agentName}: Discuss features and review PRD proposals. /save applies the preview; /draft saves unresolved drafts; /discard drops it; /exit ends. Ctrl+C cancels.\n`);
|
|
81179
81954
|
while (!io.signal.aborted) {
|
|
81180
|
-
const message = (
|
|
81955
|
+
const message = (_c = (await io.readMessage())) === null || _c === void 0 ? void 0 : _c.trim();
|
|
81181
81956
|
if (message === undefined || ['/exit', 'exit', 'quit'].includes(message))
|
|
81182
81957
|
break;
|
|
81183
81958
|
if (!message)
|
|
@@ -81314,7 +82089,7 @@ const DEFAULT_WAIT_AFTER_ERROR_MS = 10 * 60 * 1000;
|
|
|
81314
82089
|
/**
|
|
81315
82090
|
* CLI usage text for this script.
|
|
81316
82091
|
*/
|
|
81317
|
-
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--agent <agent-book-path>] [--context <context-or-file>] [--
|
|
82092
|
+
const USAGE = 'Usage: run-codex-prompts [--dry-run] [--harness <harness-name>] [--model <model>] [--agent <agent-book-path>] [--context <context-or-file>] [--check <check-command...>] [--check-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]';
|
|
81318
82093
|
/**
|
|
81319
82094
|
* Top-level flags supported by this command.
|
|
81320
82095
|
*/
|
|
@@ -81324,8 +82099,8 @@ const KNOWN_OPTION_FLAGS = new Set([
|
|
|
81324
82099
|
'--model',
|
|
81325
82100
|
'--agent',
|
|
81326
82101
|
'--context',
|
|
81327
|
-
'--
|
|
81328
|
-
'--
|
|
82102
|
+
'--check',
|
|
82103
|
+
'--check-before',
|
|
81329
82104
|
'--preserve-logs',
|
|
81330
82105
|
'--isolate',
|
|
81331
82106
|
'--no-ui',
|
|
@@ -81351,6 +82126,15 @@ const KNOWN_OPTION_FLAGS = new Set([
|
|
|
81351
82126
|
* Parses CLI arguments into runner options.
|
|
81352
82127
|
*/
|
|
81353
82128
|
function parseRunOptions(args) {
|
|
82129
|
+
args = args.flatMap((argument) => {
|
|
82130
|
+
const match = argument.match(/^(--check(?:-before)?)=([\s\S]*)$/u);
|
|
82131
|
+
return match ? [match[1], match[2]] : [argument];
|
|
82132
|
+
});
|
|
82133
|
+
for (const [legacyFlag, replacementFlag] of LEGACY_CODER_CHECK_OPTIONS) {
|
|
82134
|
+
if (args.some((argument) => argument === legacyFlag || argument.startsWith(`${legacyFlag}=`))) {
|
|
82135
|
+
exitWithUsageError(formatLegacyCoderCheckOptionError(legacyFlag, replacementFlag));
|
|
82136
|
+
}
|
|
82137
|
+
}
|
|
81354
82138
|
let agentName = undefined;
|
|
81355
82139
|
const dryRun = args.includes('--dry-run');
|
|
81356
82140
|
const harnessValue = readOptionValue(args, '--harness');
|
|
@@ -81366,10 +82150,10 @@ function parseRunOptions(args) {
|
|
|
81366
82150
|
exitWithUsageError('Pass a non-empty Book path after `--agent`, or omit it to use `agents/developer.book`.');
|
|
81367
82151
|
}
|
|
81368
82152
|
const context = readOptionValue(args, '--context');
|
|
81369
|
-
const
|
|
81370
|
-
const
|
|
81371
|
-
const
|
|
81372
|
-
const
|
|
82153
|
+
const hasCheckCommandFlag = args.includes('--check');
|
|
82154
|
+
const checkCommand = readVariadicOptionValue(args, '--check');
|
|
82155
|
+
const hasCheckBeforeFlag = args.includes('--check-before');
|
|
82156
|
+
const checkBefore = parseCheckBeforeOption(readOptionValue(args, '--check-before'), hasCheckBeforeFlag);
|
|
81373
82157
|
const preserveLogs = args.includes('--preserve-logs');
|
|
81374
82158
|
const isIsolated = args.includes('--isolate');
|
|
81375
82159
|
const noUi = args.includes('--no-ui');
|
|
@@ -81407,8 +82191,8 @@ function parseRunOptions(args) {
|
|
|
81407
82191
|
const waitBetweenPrompts = parseWaitOption(args, '--wait-between-prompts', 0);
|
|
81408
82192
|
const waitAfterError = parseWaitOption(args, '--wait-after-error', DEFAULT_WAIT_AFTER_ERROR_MS);
|
|
81409
82193
|
let thinkingLevel;
|
|
81410
|
-
if (
|
|
81411
|
-
exitWithUsageError('Missing value for --
|
|
82194
|
+
if (hasCheckCommandFlag && checkCommand === undefined) {
|
|
82195
|
+
exitWithUsageError('Missing value for --check. Use a shell command such as `npm run check` and quote it when it contains top-level CLI flags.');
|
|
81412
82196
|
}
|
|
81413
82197
|
if (hasThinkingLevelFlag && thinkingLevelValue === undefined) {
|
|
81414
82198
|
exitWithUsageError(`Missing value for --thinking-level. Use one of: ${THINKING_LEVEL_VALUES.join(', ')}.`);
|
|
@@ -81443,8 +82227,8 @@ function parseRunOptions(args) {
|
|
|
81443
82227
|
model,
|
|
81444
82228
|
agent,
|
|
81445
82229
|
context,
|
|
81446
|
-
|
|
81447
|
-
|
|
82230
|
+
checkCommand: resolveCoderCheckCommand(checkCommand, checkBefore),
|
|
82231
|
+
checkBefore,
|
|
81448
82232
|
thinkingLevel,
|
|
81449
82233
|
priority: minimumPriority !== null && minimumPriority !== void 0 ? minimumPriority : 0,
|
|
81450
82234
|
minimumPriority,
|
|
@@ -81456,15 +82240,15 @@ function parseRunOptions(args) {
|
|
|
81456
82240
|
/**
|
|
81457
82241
|
* Parses and validates the optional pre-coding verification mode.
|
|
81458
82242
|
*/
|
|
81459
|
-
function
|
|
82243
|
+
function parseCheckBeforeOption(value, hasCheckBeforeFlag) {
|
|
81460
82244
|
if (value === undefined) {
|
|
81461
|
-
if (
|
|
81462
|
-
exitWithUsageError(`Missing value for --
|
|
82245
|
+
if (hasCheckBeforeFlag) {
|
|
82246
|
+
exitWithUsageError(`Missing value for --check-before. Use one of: ${CHECK_BEFORE_MODE_VALUES.join(', ')}.`);
|
|
81463
82247
|
}
|
|
81464
82248
|
return 'no';
|
|
81465
82249
|
}
|
|
81466
|
-
if (!
|
|
81467
|
-
exitWithUsageError(`Invalid value for --
|
|
82250
|
+
if (!isCheckBeforeMode(value)) {
|
|
82251
|
+
exitWithUsageError(`Invalid value for --check-before: "${value}". Use one of: ${CHECK_BEFORE_MODE_VALUES.join(', ')}.`);
|
|
81468
82252
|
}
|
|
81469
82253
|
return value;
|
|
81470
82254
|
}
|
|
@@ -81525,8 +82309,14 @@ function readVariadicOptionValue(args, flag) {
|
|
|
81525
82309
|
}
|
|
81526
82310
|
valueParts.push(valuePart);
|
|
81527
82311
|
}
|
|
81528
|
-
|
|
81529
|
-
|
|
82312
|
+
if (valueParts.length === 0)
|
|
82313
|
+
return undefined;
|
|
82314
|
+
try {
|
|
82315
|
+
return normalizeCheckCommandOption(valueParts);
|
|
82316
|
+
}
|
|
82317
|
+
catch (error) {
|
|
82318
|
+
exitWithUsageError(error instanceof Error ? error.message : String(error));
|
|
82319
|
+
}
|
|
81530
82320
|
}
|
|
81531
82321
|
/**
|
|
81532
82322
|
* Parses and validates one priority boundary.
|
|
@@ -81968,18 +82758,6 @@ async function sleepWithCountdown(options) {
|
|
|
81968
82758
|
});
|
|
81969
82759
|
}
|
|
81970
82760
|
|
|
81971
|
-
/**
|
|
81972
|
-
* Resolves optional coding context provided inline or via a file path.
|
|
81973
|
-
*/
|
|
81974
|
-
async function resolveCoderContext(contextReference, currentWorkingDirectory) {
|
|
81975
|
-
return resolveInlineOrFileText({
|
|
81976
|
-
textReference: contextReference,
|
|
81977
|
-
currentWorkingDirectory,
|
|
81978
|
-
contextLabel: 'Coding context',
|
|
81979
|
-
optionName: '--context',
|
|
81980
|
-
});
|
|
81981
|
-
}
|
|
81982
|
-
|
|
81983
82761
|
/**
|
|
81984
82762
|
* Listens for the terminal control keys while the plain console output is used.
|
|
81985
82763
|
*
|
|
@@ -83574,7 +84352,7 @@ function buildScriptPath(file, section, projectPath = process.cwd()) {
|
|
|
83574
84352
|
*/
|
|
83575
84353
|
const CODER_RUN_STEP_LABELS = {
|
|
83576
84354
|
implementation: 'Implementation',
|
|
83577
|
-
|
|
84355
|
+
checking: 'Checking',
|
|
83578
84356
|
fixing: 'Fixing',
|
|
83579
84357
|
};
|
|
83580
84358
|
/**
|
|
@@ -83585,16 +84363,16 @@ const IN_PROGRESS_STEP_SUFFIX = 'in progress';
|
|
|
83585
84363
|
* Formats the per-step usage breakdown recorded for one prompt.
|
|
83586
84364
|
*
|
|
83587
84365
|
* Produces a `; `-separated summary such as
|
|
83588
|
-
* `Implementation $8.01 6 hours;
|
|
84366
|
+
* `Implementation $8.01 6 hours; Checking 1 hour; Fixing $3.14 2 hours` where each coding step carries its
|
|
83589
84367
|
* price and duration and each verification step carries only its duration.
|
|
83590
84368
|
*
|
|
83591
84369
|
* @param steps - Steps which have already finished
|
|
83592
|
-
* @param inProgressStepKind - Step which has started but has not finished yet, appended as `
|
|
84370
|
+
* @param inProgressStepKind - Step which has started but has not finished yet, appended as `Checking in progress`
|
|
83593
84371
|
*/
|
|
83594
84372
|
function formatCoderRunSteps(steps, inProgressStepKind) {
|
|
83595
84373
|
const formattedSteps = steps.map(formatCoderRunStep);
|
|
83596
84374
|
if (inProgressStepKind !== undefined) {
|
|
83597
|
-
formattedSteps.push(`${CODER_RUN_STEP_LABELS[inProgressStepKind]} ${IN_PROGRESS_STEP_SUFFIX}`);
|
|
84375
|
+
formattedSteps.push(`${CODER_RUN_STEP_LABELS[decodeCoderRunStepKind(inProgressStepKind)]} ${IN_PROGRESS_STEP_SUFFIX}`);
|
|
83598
84376
|
}
|
|
83599
84377
|
return formattedSteps.join('; ');
|
|
83600
84378
|
}
|
|
@@ -83602,7 +84380,7 @@ function formatCoderRunSteps(steps, inProgressStepKind) {
|
|
|
83602
84380
|
* Formats one coder run step as `Label $price duration`, omitting the price for steps without model usage.
|
|
83603
84381
|
*/
|
|
83604
84382
|
function formatCoderRunStep(step) {
|
|
83605
|
-
const label = CODER_RUN_STEP_LABELS[step.kind];
|
|
84383
|
+
const label = CODER_RUN_STEP_LABELS[decodeCoderRunStepKind(step.kind)];
|
|
83606
84384
|
const durationString = moment.duration(step.durationMs).humanize();
|
|
83607
84385
|
const priceString = step.usage === null ? undefined : formatUsagePrice(step.usage);
|
|
83608
84386
|
if (priceString === undefined) {
|
|
@@ -83610,6 +84388,10 @@ function formatCoderRunStep(step) {
|
|
|
83610
84388
|
}
|
|
83611
84389
|
return `${label} ${priceString} ${durationString}`;
|
|
83612
84390
|
}
|
|
84391
|
+
/** Decodes the old aggregate step name at the display boundary; new execution only records checking. */
|
|
84392
|
+
function decodeCoderRunStepKind(kind) {
|
|
84393
|
+
return kind === 'testing' ? 'checking' : kind;
|
|
84394
|
+
}
|
|
83613
84395
|
|
|
83614
84396
|
/**
|
|
83615
84397
|
* Formats optional attempt metadata stored in prompt status lines.
|
|
@@ -83950,13 +84732,13 @@ function buildPromptRunTraceSummarySection(options) {
|
|
|
83950
84732
|
`- **Runner:** ${runnerSignature}${loginMethodSuffix}`,
|
|
83951
84733
|
`- **Attempts:** ${options.attemptCount}`,
|
|
83952
84734
|
...buildPromptRunTraceStepsLines(outcome),
|
|
83953
|
-
...
|
|
84735
|
+
...buildPromptRunTraceCheckCommandLines(options.checkCommand),
|
|
83954
84736
|
`- **Started:** ${options.startedDate.toISOString()}`,
|
|
83955
84737
|
`- **Finished:** ${options.finishedDate.toISOString()}`,
|
|
83956
84738
|
`- **Duration:** ${moment.duration(options.finishedDate.diff(options.startedDate)).humanize()}`,
|
|
83957
84739
|
];
|
|
83958
84740
|
return spaceTrim$1((block) => `
|
|
83959
|
-
# Run trace of \`${buildPromptLabelForDisplay(file, section)}\`
|
|
84741
|
+
# Run trace of \`${buildPromptLabelForDisplay(file, section, options.projectPath)}\`
|
|
83960
84742
|
|
|
83961
84743
|
${block(detailLines.join('\n'))}
|
|
83962
84744
|
`);
|
|
@@ -83989,11 +84771,11 @@ function buildPromptRunTraceStepsLines(outcome) {
|
|
|
83989
84771
|
/**
|
|
83990
84772
|
* Renders the verification command of the round, omitted when the round ran without one.
|
|
83991
84773
|
*/
|
|
83992
|
-
function
|
|
83993
|
-
if (!
|
|
84774
|
+
function buildPromptRunTraceCheckCommandLines(checkCommand) {
|
|
84775
|
+
if (!checkCommand) {
|
|
83994
84776
|
return [];
|
|
83995
84777
|
}
|
|
83996
|
-
return [`- **
|
|
84778
|
+
return [`- **Check command:** \`${checkCommand}\``];
|
|
83997
84779
|
}
|
|
83998
84780
|
/**
|
|
83999
84781
|
* Renders the failure details of a failed round, omitted for a successful one.
|
|
@@ -84080,9 +84862,9 @@ const MAX_RETRY_ATTEMPTS_AFTER_ERROR = 3;
|
|
|
84080
84862
|
*
|
|
84081
84863
|
* @private function of runCodexPrompts
|
|
84082
84864
|
*/
|
|
84083
|
-
async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, promptLabel, resolvedCoderContext, resolvedAgentSystemMessage, isRichUiEnabled, progressDisplay, uiHandle, waitForRequestedPause, projectPath, }) {
|
|
84084
|
-
var _a, _b;
|
|
84085
|
-
const roundProjectPath = (_b = projectPath !== null && projectPath !== void 0 ? projectPath : (_a = options.workspace) === null || _a === void 0 ? void 0 : _a.projectPath) !== null && _b !== void 0 ? _b : process.cwd();
|
|
84865
|
+
async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, promptLabel, resolvedCoderContext, resolvedAgentSystemMessage, isRichUiEnabled, progressDisplay, uiHandle, waitForRequestedPause, projectPath, artifactsProjectPath, }) {
|
|
84866
|
+
var _a, _b, _c;
|
|
84867
|
+
const roundProjectPath = (_c = (_b = projectPath !== null && projectPath !== void 0 ? projectPath : (_a = options.workspace) === null || _a === void 0 ? void 0 : _a.projectPath) !== null && _b !== void 0 ? _b : options.projectPath) !== null && _c !== void 0 ? _c : process.cwd();
|
|
84086
84868
|
const commitMessage = buildCommitMessage(nextPrompt.file, nextPrompt.section);
|
|
84087
84869
|
const taskPrompt = buildCodexPrompt(nextPrompt.file, nextPrompt.section);
|
|
84088
84870
|
// Prepend agent system message before the task so the harness sees agent instructions first
|
|
@@ -84099,8 +84881,7 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
84099
84881
|
`)
|
|
84100
84882
|
: taskPrompt;
|
|
84101
84883
|
const codexPrompt = appendCoderContext(promptWithAgent, resolvedCoderContext);
|
|
84102
|
-
|
|
84103
|
-
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section);
|
|
84884
|
+
const scriptPath = buildScriptPath(nextPrompt.file, nextPrompt.section, artifactsProjectPath !== null && artifactsProjectPath !== void 0 ? artifactsProjectPath : roundProjectPath);
|
|
84104
84885
|
// Note: Read before the first `[^]` rewrite of this round, which would overwrite the report recorded so far
|
|
84105
84886
|
const previousRunnerSignatures = resolvePreviousRunnerSignatures(nextPrompt);
|
|
84106
84887
|
setPromptRoundRunningState({ isRichUiEnabled, promptLabel, scriptPath, uiHandle });
|
|
@@ -84119,13 +84900,13 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
84119
84900
|
for (let errorRetryAttempt = 0; errorRetryAttempt <= MAX_RETRY_ATTEMPTS_AFTER_ERROR; errorRetryAttempt++) {
|
|
84120
84901
|
try {
|
|
84121
84902
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
84122
|
-
const result = await
|
|
84903
|
+
const result = await runPromptWithCheckFeedback({
|
|
84123
84904
|
runner,
|
|
84124
84905
|
prompt: codexPrompt,
|
|
84125
84906
|
scriptPath,
|
|
84126
84907
|
projectPath: roundProjectPath,
|
|
84127
84908
|
promptLabel,
|
|
84128
|
-
|
|
84909
|
+
checkCommand: options.checkCommand,
|
|
84129
84910
|
preserveArtifactsOnSuccess: options.preserveLogs,
|
|
84130
84911
|
logPath,
|
|
84131
84912
|
onAttemptStarted: (nextAttemptCount) => {
|
|
@@ -84165,7 +84946,9 @@ async function runPromptRound({ options, runner, runnerMetadata, nextPrompt, pro
|
|
|
84165
84946
|
lastError = error;
|
|
84166
84947
|
// Note: A harness which is not logged in answers every retry the same way, so the user gets
|
|
84167
84948
|
// the sign-in instructions right away instead of after every retry has waited its delay
|
|
84168
|
-
if (error instanceof AuthenticationError ||
|
|
84949
|
+
if (error instanceof AuthenticationError ||
|
|
84950
|
+
error instanceof CoderCheckSetupError ||
|
|
84951
|
+
errorRetryAttempt >= MAX_RETRY_ATTEMPTS_AFTER_ERROR) {
|
|
84169
84952
|
break;
|
|
84170
84953
|
}
|
|
84171
84954
|
await waitAfterErrorBeforeRetry({
|
|
@@ -84407,13 +85190,15 @@ async function finalizeFailedPromptRound(options) {
|
|
|
84407
85190
|
* harness, model and thinking level did it and everything that harness has written while doing it.
|
|
84408
85191
|
*/
|
|
84409
85192
|
async function recordPromptRoundTrace(options) {
|
|
85193
|
+
var _a, _b;
|
|
84410
85194
|
const { options: runOptions, nextPrompt, runnerMetadata, promptExecutionStartedDate, attemptCount, logPath, outcome, } = options;
|
|
84411
85195
|
await writePromptRunTrace({
|
|
85196
|
+
projectPath: (_b = (_a = runOptions.workspace) === null || _a === void 0 ? void 0 : _a.projectPath) !== null && _b !== void 0 ? _b : runOptions.projectPath,
|
|
84412
85197
|
file: nextPrompt.file,
|
|
84413
85198
|
section: nextPrompt.section,
|
|
84414
85199
|
...runnerMetadata,
|
|
84415
85200
|
thinkingLevel: runOptions.thinkingLevel,
|
|
84416
|
-
|
|
85201
|
+
checkCommand: runOptions.checkCommand,
|
|
84417
85202
|
attemptCount,
|
|
84418
85203
|
startedDate: promptExecutionStartedDate,
|
|
84419
85204
|
finishedDate: moment(),
|
|
@@ -85011,12 +85796,12 @@ async function abortSquashMerge(worktree) {
|
|
|
85011
85796
|
* @private function of runCodexPrompts
|
|
85012
85797
|
*/
|
|
85013
85798
|
async function runIsolatedPromptRound(options) {
|
|
85014
|
-
var _a, _b, _c, _d, _e, _f;
|
|
85799
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
85015
85800
|
const { nextPrompt, promptLabel, isRichUiEnabled, uiHandle, waitForRequestedPause } = options;
|
|
85016
|
-
const projectPath = (_c = (_a = options.projectPath) !== null && _a !== void 0 ? _a : (_b = options.options.workspace) === null || _b === void 0 ? void 0 : _b.projectPath) !== null && _c !== void 0 ? _c : process.cwd();
|
|
85801
|
+
const projectPath = (_d = (_c = (_a = options.projectPath) !== null && _a !== void 0 ? _a : (_b = options.options.workspace) === null || _b === void 0 ? void 0 : _b.projectPath) !== null && _c !== void 0 ? _c : options.options.projectPath) !== null && _d !== void 0 ? _d : process.cwd();
|
|
85017
85802
|
// Note: The original project is left untouched by the isolated round itself, so its scope covers exactly
|
|
85018
85803
|
// the prompt status update and the changes the merge brings back from the worktree
|
|
85019
|
-
const originalProjectCommitScope = await captureCoderCommitScope((
|
|
85804
|
+
const originalProjectCommitScope = await captureCoderCommitScope((_e = options.options.workspace) !== null && _e !== void 0 ? _e : projectPath);
|
|
85020
85805
|
const worktree = await createCoderIsolationWorktree({
|
|
85021
85806
|
projectPath,
|
|
85022
85807
|
repositoryRoot: originalProjectCommitScope.repositoryRoot,
|
|
@@ -85024,16 +85809,44 @@ async function runIsolatedPromptRound(options) {
|
|
|
85024
85809
|
});
|
|
85025
85810
|
announceIsolatedRoundStart(worktree, promptLabel, isRichUiEnabled);
|
|
85026
85811
|
try {
|
|
85027
|
-
const isolatedProjectPath = join(worktree.worktreePath, relative((
|
|
85812
|
+
const isolatedProjectPath = join(worktree.worktreePath, relative((_f = originalProjectCommitScope.repositoryRoot) !== null && _f !== void 0 ? _f : projectPath, projectPath));
|
|
85028
85813
|
// This newly created working tree has its own metadata. Keep the project's repository-relative
|
|
85029
85814
|
// location so its harness and verification use the same project as the original invocation.
|
|
85030
85815
|
const isolatedWorkspace = await $resolveWorkspaceRepository(isolatedProjectPath);
|
|
85816
|
+
const isolatedOptions = {
|
|
85817
|
+
...options.options,
|
|
85818
|
+
workspace: isolatedWorkspace,
|
|
85819
|
+
projectPath: isolatedWorkspace.projectPath,
|
|
85820
|
+
agent: mapProjectReferenceToWorktree(options.options.agent, (_g = originalProjectCommitScope.repositoryRoot) !== null && _g !== void 0 ? _g : projectPath, worktree.worktreePath),
|
|
85821
|
+
context: mapProjectReferenceToWorktree(options.options.context, (_h = originalProjectCommitScope.repositoryRoot) !== null && _h !== void 0 ? _h : projectPath, worktree.worktreePath),
|
|
85822
|
+
autoPush: false,
|
|
85823
|
+
};
|
|
85824
|
+
const projectContext = await resolveCoderProjectContext(isolatedOptions);
|
|
85825
|
+
const agent = await resolveCoderAgent(isolatedOptions.agent, isolatedWorkspace.projectPath, {
|
|
85826
|
+
defaultRole: DEFAULT_CODER_AGENT_ROLE,
|
|
85827
|
+
isInitializationAllowed: false,
|
|
85828
|
+
});
|
|
85829
|
+
// Status updates, traces and commits belong to the same checkout as the harness and checks.
|
|
85830
|
+
// Copy the parsed data too, so a failed isolated round does not mutate the original queue in memory.
|
|
85831
|
+
const isolatedFile = {
|
|
85832
|
+
...nextPrompt.file,
|
|
85833
|
+
path: join(isolatedWorkspace.projectPath, relative(projectPath, nextPrompt.file.path)),
|
|
85834
|
+
lines: [...nextPrompt.file.lines],
|
|
85835
|
+
sections: nextPrompt.file.sections.map((section) => ({ ...section })),
|
|
85836
|
+
};
|
|
85031
85837
|
await runPromptRound({
|
|
85032
85838
|
...options,
|
|
85839
|
+
nextPrompt: { file: isolatedFile, section: isolatedFile.sections[nextPrompt.section.index] },
|
|
85033
85840
|
projectPath: isolatedWorkspace.projectPath,
|
|
85841
|
+
// Temporary scripts and raw logs deliberately outlive the worktree; PRDs and traces are merged.
|
|
85842
|
+
artifactsProjectPath: projectPath,
|
|
85843
|
+
resolvedCoderContext: projectContext.context,
|
|
85844
|
+
resolvedAgentSystemMessage: agent === null || agent === void 0 ? void 0 : agent.systemMessage,
|
|
85034
85845
|
// Note: The isolated commit must never reach the remote, the merged commit on the original branch is pushed instead
|
|
85035
|
-
options: { ...
|
|
85846
|
+
options: { ...isolatedOptions, projectContext },
|
|
85036
85847
|
});
|
|
85848
|
+
// Keep the display/commit identity in sync without writing to the original checkout before merging.
|
|
85849
|
+
Object.assign(nextPrompt.section, isolatedFile.sections[nextPrompt.section.index]);
|
|
85037
85850
|
}
|
|
85038
85851
|
catch (error) {
|
|
85039
85852
|
// Note: The worktree keeps whatever the failed round produced, which would be lost by deleting it here
|
|
@@ -85054,7 +85867,7 @@ async function runIsolatedPromptRound(options) {
|
|
|
85054
85867
|
await commitChanges(buildCommitMessage(nextPrompt.file, nextPrompt.section), {
|
|
85055
85868
|
autoPush: options.options.autoPush,
|
|
85056
85869
|
relevantPaths: await resolveCoderCommitScopePaths(originalProjectCommitScope),
|
|
85057
|
-
projectPath: (
|
|
85870
|
+
projectPath: (_j = originalProjectCommitScope.repositoryRoot) !== null && _j !== void 0 ? _j : projectPath,
|
|
85058
85871
|
});
|
|
85059
85872
|
await removeCoderIsolationWorktree(worktree);
|
|
85060
85873
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Merged \`${worktree.taskName}\` into \`${worktree.baseBranchName}\``);
|
|
@@ -85063,9 +85876,23 @@ async function runIsolatedPromptRound(options) {
|
|
|
85063
85876
|
* Records a failed isolation merge in the original project and keeps the worktree for a manual merge.
|
|
85064
85877
|
*/
|
|
85065
85878
|
async function recordIsolationMergeFailure(options, worktree, failureDetails) {
|
|
85066
|
-
var _a, _b;
|
|
85879
|
+
var _a, _b, _c, _d;
|
|
85067
85880
|
const { nextPrompt, runnerMetadata, isRichUiEnabled, uiHandle } = options;
|
|
85068
85881
|
const mergeFailureError = buildCoderIsolationMergeFailureError(worktree, failureDetails);
|
|
85882
|
+
const repositoryRoot = (_b = (_a = options.options.workspace) === null || _a === void 0 ? void 0 : _a.repositoryRoot) !== null && _b !== void 0 ? _b : worktree.projectPath;
|
|
85883
|
+
const tracePath = buildPromptRunTracePath(nextPrompt.file, nextPrompt.section);
|
|
85884
|
+
const isolatedTracePath = join(worktree.worktreePath, relative(repositoryRoot, tracePath));
|
|
85885
|
+
// The failed merge did not bring back the worktree's trace. Preserve it beside the failure report.
|
|
85886
|
+
await mkdir(dirname(tracePath), { recursive: true });
|
|
85887
|
+
let isTraceCopied = false;
|
|
85888
|
+
try {
|
|
85889
|
+
await copyFile(isolatedTracePath, tracePath);
|
|
85890
|
+
isTraceCopied = true;
|
|
85891
|
+
}
|
|
85892
|
+
catch (error) {
|
|
85893
|
+
if (error.code !== 'ENOENT')
|
|
85894
|
+
throw error;
|
|
85895
|
+
}
|
|
85069
85896
|
markPromptIsolationMergeFailed(nextPrompt.file, nextPrompt.section, worktree);
|
|
85070
85897
|
await writePromptFile(nextPrompt.file);
|
|
85071
85898
|
const errorLogPath = await writePromptErrorLog({
|
|
@@ -85077,13 +85904,11 @@ async function recordIsolationMergeFailure(options, worktree, failureDetails) {
|
|
|
85077
85904
|
});
|
|
85078
85905
|
await commitChanges(buildCoderIsolationMergeFailureCommitMessage(worktree), {
|
|
85079
85906
|
autoPush: options.options.autoPush,
|
|
85080
|
-
projectPath: (
|
|
85081
|
-
// Note: The round itself has already succeeded, so it has left its run trace in the original project.
|
|
85082
|
-
// It belongs to this commit, which is the only one this task still gets.
|
|
85907
|
+
projectPath: (_d = (_c = options.options.workspace) === null || _c === void 0 ? void 0 : _c.repositoryRoot) !== null && _d !== void 0 ? _d : worktree.projectPath,
|
|
85083
85908
|
relevantPaths: [
|
|
85084
85909
|
nextPrompt.file.path,
|
|
85085
85910
|
errorLogPath,
|
|
85086
|
-
|
|
85911
|
+
...(isTraceCopied ? [tracePath] : []),
|
|
85087
85912
|
].map((path) => { var _a, _b; return toProjectRelativeGitPath((_b = (_a = options.options.workspace) === null || _a === void 0 ? void 0 : _a.repositoryRoot) !== null && _b !== void 0 ? _b : worktree.projectPath, path); }),
|
|
85088
85913
|
});
|
|
85089
85914
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.addError(mergeFailureError.message);
|
|
@@ -85124,8 +85949,8 @@ function findNextTodoPrompt(files, priorityFilter = {}, promptRunnerIdentity) {
|
|
|
85124
85949
|
/**
|
|
85125
85950
|
* Builds a label that identifies the prompt section by index.
|
|
85126
85951
|
*/
|
|
85127
|
-
function buildPromptLabel(file, section) {
|
|
85128
|
-
return `${relative(
|
|
85952
|
+
function buildPromptLabel(file, section, projectPath = process.cwd()) {
|
|
85953
|
+
return `${relative(projectPath, file.path).replace(/\\/g, '/')}#${section.index + 1}`;
|
|
85129
85954
|
}
|
|
85130
85955
|
|
|
85131
85956
|
/**
|
|
@@ -85353,18 +86178,20 @@ function startCoderRunUiSubscriptionUsageRefresh(options) {
|
|
|
85353
86178
|
}
|
|
85354
86179
|
|
|
85355
86180
|
/**
|
|
85356
|
-
* Creates the one queue prompt used to repair a pre-existing
|
|
86181
|
+
* Creates the one queue prompt used to repair a pre-existing project check failure.
|
|
85357
86182
|
*/
|
|
85358
|
-
async function
|
|
86183
|
+
async function createCheckBeforeRepairPrompt(options) {
|
|
85359
86184
|
const description = spaceTrim((block) => `
|
|
85360
|
-
Fix the existing
|
|
86185
|
+
Fix the existing check failures before implementing any queued coding tasks.
|
|
86186
|
+
|
|
86187
|
+
The check command \`${options.checkCommand}\` failed before coding started. Leave the project ready for the remaining coding prompts.
|
|
85361
86188
|
|
|
85362
|
-
|
|
86189
|
+
${block(CHECK_REPAIR_INSTRUCTIONS)}
|
|
85363
86190
|
|
|
85364
|
-
##
|
|
86191
|
+
## Check output
|
|
85365
86192
|
|
|
85366
86193
|
\`\`\`
|
|
85367
|
-
${block(
|
|
86194
|
+
${block(limitCheckOutput(options.checkOutput))}
|
|
85368
86195
|
\`\`\`
|
|
85369
86196
|
`);
|
|
85370
86197
|
const createdPrompt = await addCoderPrompt({
|
|
@@ -85377,50 +86204,56 @@ async function createTestBeforeRepairPrompt(options) {
|
|
|
85377
86204
|
const section = promptFile.sections[0];
|
|
85378
86205
|
if (!section) {
|
|
85379
86206
|
throw new UnexpectedError(spaceTrim(`
|
|
85380
|
-
The pre-coding
|
|
86207
|
+
The pre-coding check repair prompt was created at \`${createdPrompt.filePath}\` without a runnable section.
|
|
85381
86208
|
`));
|
|
85382
86209
|
}
|
|
85383
86210
|
return { file: promptFile, section };
|
|
85384
86211
|
}
|
|
85385
86212
|
|
|
85386
86213
|
/**
|
|
85387
|
-
* Runs the configured
|
|
86214
|
+
* Runs the configured check command before the first coding prompt.
|
|
85388
86215
|
*/
|
|
85389
|
-
async function
|
|
85390
|
-
var _a, _b;
|
|
85391
|
-
|
|
85392
|
-
const
|
|
85393
|
-
|
|
85394
|
-
|
|
86216
|
+
async function runCheckBefore(options) {
|
|
86217
|
+
var _a, _b, _c, _d, _e, _f;
|
|
86218
|
+
(_a = options.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
86219
|
+
const runPromptCheckCommandExecutor = (_b = options.runPromptCheckCommandExecutor) !== null && _b !== void 0 ? _b : runPromptCheckCommand;
|
|
86220
|
+
const initialCheckStatusMessage = `Running initial checks before the agent coding starts: ${options.checkCommand}`;
|
|
86221
|
+
await ((_c = options.waitForPauseCheckpoint) === null || _c === void 0 ? void 0 : _c.call(options, {
|
|
86222
|
+
checkpointLabel: 'running initial checks before the agent coding starts',
|
|
85395
86223
|
phase: 'verifying',
|
|
85396
|
-
statusMessage:
|
|
86224
|
+
statusMessage: initialCheckStatusMessage,
|
|
85397
86225
|
}));
|
|
85398
|
-
|
|
86226
|
+
(_d = options.signal) === null || _d === void 0 ? void 0 : _d.throwIfAborted();
|
|
86227
|
+
console.info(colors.gray(initialCheckStatusMessage));
|
|
85399
86228
|
try {
|
|
85400
|
-
const
|
|
85401
|
-
command: options.
|
|
86229
|
+
const checkOutput = await runPromptCheckCommandExecutor({
|
|
86230
|
+
command: options.checkCommand,
|
|
85402
86231
|
projectPath: options.projectPath,
|
|
85403
86232
|
scriptPath: buildTemporaryPromptScriptPath({
|
|
85404
86233
|
projectPath: options.projectPath,
|
|
85405
86234
|
scriptDirectoryName: 'coder-prompts',
|
|
85406
|
-
sourceFileName: '
|
|
86235
|
+
sourceFileName: 'check-before',
|
|
85407
86236
|
}),
|
|
86237
|
+
...(options.signal ? { signal: options.signal } : {}),
|
|
85408
86238
|
});
|
|
85409
|
-
|
|
85410
|
-
|
|
86239
|
+
(_e = options.signal) === null || _e === void 0 ? void 0 : _e.throwIfAborted();
|
|
86240
|
+
console.info(colors.green('Pre-coding checks passed.'));
|
|
86241
|
+
return { isPassed: true, checkOutput };
|
|
85411
86242
|
}
|
|
85412
86243
|
catch (error) {
|
|
85413
|
-
|
|
85414
|
-
|
|
85415
|
-
|
|
85416
|
-
|
|
86244
|
+
if (error instanceof CoderCheckSetupError || ((_f = options.signal) === null || _f === void 0 ? void 0 : _f.aborted))
|
|
86245
|
+
throw error;
|
|
86246
|
+
const checkOutput = formatUnknownErrorMessage(error);
|
|
86247
|
+
console.error(colors.red('Pre-coding checks failed.'));
|
|
86248
|
+
console.error(checkOutput);
|
|
86249
|
+
return { isPassed: false, checkOutput };
|
|
85417
86250
|
}
|
|
85418
86251
|
}
|
|
85419
86252
|
|
|
85420
86253
|
/**
|
|
85421
|
-
* Commit message for files changed by a successful or failed pre-coding
|
|
86254
|
+
* Commit message for files changed by a successful or failed pre-coding check in repair mode.
|
|
85422
86255
|
*/
|
|
85423
|
-
const
|
|
86256
|
+
const PRE_CODING_CHECK_CHANGES_COMMIT_MESSAGE = 'chore: Apply changes made by pre-coding checks';
|
|
85424
86257
|
/**
|
|
85425
86258
|
* Main entry point for running prompts with the selected agent.
|
|
85426
86259
|
*
|
|
@@ -85429,10 +86262,15 @@ const PRE_CODING_TEST_CHANGES_COMMIT_MESSAGE = 'test: Apply changes made by pre-
|
|
|
85429
86262
|
* @public exported from `@promptbook/cli`
|
|
85430
86263
|
*/
|
|
85431
86264
|
async function runCodexPrompts(providedOptions) {
|
|
85432
|
-
var _a, _b, _c, _d;
|
|
85433
|
-
const
|
|
85434
|
-
validateCoderRunOptions(
|
|
85435
|
-
|
|
86265
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
86266
|
+
const normalizedOptions = normalizeRunOptions(providedOptions !== null && providedOptions !== void 0 ? providedOptions : parseRunOptions(process.argv.slice(2)));
|
|
86267
|
+
validateCoderRunOptions(normalizedOptions);
|
|
86268
|
+
// CLI-preflighted workspaces are already canonical. For direct runs without an explicit project path, preserve
|
|
86269
|
+
// `process.cwd()` as written because macOS may expose the same temporary directory through `/var` and `/private/var`.
|
|
86270
|
+
const projectPath = (_b = (_a = normalizedOptions.workspace) === null || _a === void 0 ? void 0 : _a.projectPath) !== null && _b !== void 0 ? _b : ((providedOptions === null || providedOptions === void 0 ? void 0 : providedOptions.projectPath) === undefined
|
|
86271
|
+
? normalizedOptions.projectPath
|
|
86272
|
+
: await resolveProjectDirectory(normalizedOptions.projectPath));
|
|
86273
|
+
const options = { ...normalizedOptions, projectPath };
|
|
85436
86274
|
resetCoderRunControls();
|
|
85437
86275
|
const runStartDate = moment();
|
|
85438
86276
|
const { isRichUiEnabled, progressDisplay, uiHandle } = createRunDisplays(options, runStartDate);
|
|
@@ -85450,20 +86288,25 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85450
86288
|
startPauseListenerIfNeeded(isRichUiEnabled);
|
|
85451
86289
|
let subscriptionUsageRefresh;
|
|
85452
86290
|
try {
|
|
85453
|
-
const
|
|
86291
|
+
const projectContext = (_d = options.projectContext) !== null && _d !== void 0 ? _d : (await resolveCoderProjectContext({
|
|
86292
|
+
...options,
|
|
86293
|
+
projectPath,
|
|
86294
|
+
}));
|
|
86295
|
+
if (await runDryRunIfRequested(options, (_e = projectContext.agentBook) === null || _e === void 0 ? void 0 : _e.agentReferences)) {
|
|
86296
|
+
return;
|
|
86297
|
+
}
|
|
86298
|
+
await assertProjectCheckIsConfigured(options.checkCommand, projectPath);
|
|
86299
|
+
const resolvedCoderContext = projectContext.context;
|
|
85454
86300
|
const resolvedCoderAgent = await resolveCoderAgent(options.agent, projectPath, {
|
|
85455
|
-
defaultRole:
|
|
86301
|
+
defaultRole: DEFAULT_CODER_AGENT_ROLE,
|
|
85456
86302
|
isInitializationAllowed: !options.dryRun,
|
|
85457
86303
|
});
|
|
85458
86304
|
const resolvedAgentSystemMessage = resolvedCoderAgent === null || resolvedCoderAgent === void 0 ? void 0 : resolvedCoderAgent.systemMessage;
|
|
85459
|
-
if (await runDryRunIfRequested(options, resolvedCoderAgent === null || resolvedCoderAgent === void 0 ? void 0 : resolvedCoderAgent.agentReferences)) {
|
|
85460
|
-
return;
|
|
85461
|
-
}
|
|
85462
86305
|
if (!options.noCommit && resolvedCoderAgent) {
|
|
85463
86306
|
await commitInitializedAgentBooks(projectPath, resolvedCoderAgent.createdAgentBookPaths, options.workspace);
|
|
85464
86307
|
}
|
|
85465
86308
|
const { runner: harnessRunner, actualRunnerModel, runnerMetadata: harnessRunnerMetadata, } = resolvePromptRunner(options);
|
|
85466
|
-
const runner = createCoderTeamPromptRunner(harnessRunner, options.agent);
|
|
86309
|
+
const runner = createCoderTeamPromptRunner(harnessRunner, options.agent, projectPath, (_f = options.workspace) === null || _f === void 0 ? void 0 : _f.repositoryRoot);
|
|
85467
86310
|
// Note: The harness only knows itself, so the Book agent it runs as is joined here - this is the single
|
|
85468
86311
|
// place where the whole run report of prompt status lines and run traces is put together
|
|
85469
86312
|
const runnerMetadata = {
|
|
@@ -85494,7 +86337,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85494
86337
|
let previousRoundStartTime;
|
|
85495
86338
|
let previousRoundEndTime;
|
|
85496
86339
|
let completedRunCount = 0;
|
|
85497
|
-
let
|
|
86340
|
+
let hasRunCheckBefore = false;
|
|
85498
86341
|
// Note: Only the very first round resumes the interrupted prompt, every later round starts from a clean tree
|
|
85499
86342
|
let isContinuingInterruptedPrompt = options.gitChanges === 'continue';
|
|
85500
86343
|
while (just(true)) {
|
|
@@ -85509,11 +86352,11 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85509
86352
|
options,
|
|
85510
86353
|
isRichUiEnabled,
|
|
85511
86354
|
});
|
|
85512
|
-
if (!
|
|
86355
|
+
if (!hasRunCheckBefore && options.checkBefore !== 'no') {
|
|
85513
86356
|
await waitForRequestedPause({
|
|
85514
|
-
checkpointLabel: 'loading prompts before running initial
|
|
86357
|
+
checkpointLabel: 'loading prompts before running initial checks',
|
|
85515
86358
|
phase: 'loading',
|
|
85516
|
-
statusMessage: 'Loading prompts before running initial
|
|
86359
|
+
statusMessage: 'Loading prompts before running initial checks...',
|
|
85517
86360
|
});
|
|
85518
86361
|
await loadPromptQueueSnapshot({
|
|
85519
86362
|
options,
|
|
@@ -85524,8 +86367,8 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85524
86367
|
isContinuingInterruptedPrompt,
|
|
85525
86368
|
});
|
|
85526
86369
|
}
|
|
85527
|
-
if (!
|
|
85528
|
-
hasWaitedForStart = await
|
|
86370
|
+
if (!hasRunCheckBefore) {
|
|
86371
|
+
hasWaitedForStart = await runCheckBeforeIfNeeded({
|
|
85529
86372
|
options,
|
|
85530
86373
|
runner,
|
|
85531
86374
|
runnerMetadata,
|
|
@@ -85538,7 +86381,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85538
86381
|
hasWaitedForStart,
|
|
85539
86382
|
isContinuingInterruptedPrompt,
|
|
85540
86383
|
});
|
|
85541
|
-
|
|
86384
|
+
hasRunCheckBefore = true;
|
|
85542
86385
|
}
|
|
85543
86386
|
await waitForRequestedPause({
|
|
85544
86387
|
checkpointLabel: 'loading prompts',
|
|
@@ -85554,6 +86397,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85554
86397
|
isContinuingInterruptedPrompt,
|
|
85555
86398
|
});
|
|
85556
86399
|
hasShownUpcomingTasks || (hasShownUpcomingTasks = showUpcomingTasksOnce({
|
|
86400
|
+
projectPath,
|
|
85557
86401
|
hasShownUpcomingTasks,
|
|
85558
86402
|
promptFiles: promptQueueSnapshot.promptFiles,
|
|
85559
86403
|
stats: promptQueueSnapshot.stats,
|
|
@@ -85584,7 +86428,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85584
86428
|
return;
|
|
85585
86429
|
}
|
|
85586
86430
|
const nextPrompt = promptQueueSnapshot.nextPrompt;
|
|
85587
|
-
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section);
|
|
86431
|
+
const promptLabel = buildPromptLabelForDisplay(nextPrompt.file, nextPrompt.section, projectPath);
|
|
85588
86432
|
// Wait between prompt rounds (skipped for the first round)
|
|
85589
86433
|
if (previousRoundStartTime !== undefined && previousRoundEndTime !== undefined) {
|
|
85590
86434
|
await waitBetweenPromptRoundsIfNeeded({
|
|
@@ -85619,7 +86463,7 @@ async function runCodexPrompts(providedOptions) {
|
|
|
85619
86463
|
phase: 'loading',
|
|
85620
86464
|
statusMessage: 'Checking the working tree...',
|
|
85621
86465
|
});
|
|
85622
|
-
await ensureWorkingTreeClean((
|
|
86466
|
+
await ensureWorkingTreeClean((_h = (_g = options.workspace) === null || _g === void 0 ? void 0 : _g.repositoryRoot) !== null && _h !== void 0 ? _h : projectPath);
|
|
85623
86467
|
}
|
|
85624
86468
|
const currentRoundStartTime = Date.now();
|
|
85625
86469
|
// Note: An isolated round implements the prompt in a temporary worktree and merges it back afterwards
|
|
@@ -85681,7 +86525,7 @@ function isCleanWorkingTreeRequired(gitChanges, isContinuingInterruptedPrompt) {
|
|
|
85681
86525
|
* Pulls the latest repository state before loading prompts when the feature is enabled.
|
|
85682
86526
|
*/
|
|
85683
86527
|
async function pullLatestChangesIfEnabled(options) {
|
|
85684
|
-
var _a;
|
|
86528
|
+
var _a, _b;
|
|
85685
86529
|
const { options: runOptions, isRichUiEnabled } = options;
|
|
85686
86530
|
if (!runOptions.autoPull || runOptions.dryRun) {
|
|
85687
86531
|
return;
|
|
@@ -85689,7 +86533,7 @@ async function pullLatestChangesIfEnabled(options) {
|
|
|
85689
86533
|
if (!isRichUiEnabled) {
|
|
85690
86534
|
console.info(colors.gray('Pulling latest changes before the next prompt...'));
|
|
85691
86535
|
}
|
|
85692
|
-
await pullLatestChanges((_a = runOptions.workspace) === null || _a === void 0 ? void 0 : _a.repositoryRoot);
|
|
86536
|
+
await pullLatestChanges((_b = (_a = runOptions.workspace) === null || _a === void 0 ? void 0 : _a.repositoryRoot) !== null && _b !== void 0 ? _b : runOptions.projectPath);
|
|
85693
86537
|
}
|
|
85694
86538
|
/**
|
|
85695
86539
|
* Creates the progress display and rich UI handles used during the run.
|
|
@@ -85714,19 +86558,19 @@ function createRunDisplays(options, runStartDate) {
|
|
|
85714
86558
|
* Normalizes legacy and current priority options into one validated run option shape.
|
|
85715
86559
|
*/
|
|
85716
86560
|
function normalizeRunOptions(options) {
|
|
85717
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
85718
|
-
const
|
|
85719
|
-
const normalizedTestCommand = (_b = options.testCommand) === null || _b === void 0 ? void 0 : _b.trim();
|
|
86561
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
86562
|
+
const checkBefore = (_a = options.checkBefore) !== null && _a !== void 0 ? _a : 'no';
|
|
85720
86563
|
const priorityFilter = normalizePriorityFilter({
|
|
85721
86564
|
priority: options.priority,
|
|
85722
|
-
minimumPriority: (
|
|
85723
|
-
maximumPriority: (
|
|
86565
|
+
minimumPriority: (_b = options.minimumPriority) !== null && _b !== void 0 ? _b : (_c = options.priorityFilter) === null || _c === void 0 ? void 0 : _c.minimumPriority,
|
|
86566
|
+
maximumPriority: (_d = options.maximumPriority) !== null && _d !== void 0 ? _d : (_e = options.priorityFilter) === null || _e === void 0 ? void 0 : _e.maximumPriority,
|
|
85724
86567
|
});
|
|
85725
86568
|
return {
|
|
85726
86569
|
...options,
|
|
85727
|
-
|
|
85728
|
-
|
|
85729
|
-
|
|
86570
|
+
projectPath: (_h = (_g = (_f = options.workspace) === null || _f === void 0 ? void 0 : _f.projectPath) !== null && _g !== void 0 ? _g : options.projectPath) !== null && _h !== void 0 ? _h : process.cwd(),
|
|
86571
|
+
checkBefore,
|
|
86572
|
+
checkCommand: resolveCoderCheckCommand((_j = options.checkCommand) === null || _j === void 0 ? void 0 : _j.trim(), checkBefore),
|
|
86573
|
+
priority: (_k = priorityFilter.minimumPriority) !== null && _k !== void 0 ? _k : 0,
|
|
85730
86574
|
minimumPriority: priorityFilter.minimumPriority,
|
|
85731
86575
|
maximumPriority: priorityFilter.maximumPriority,
|
|
85732
86576
|
priorityFilter,
|
|
@@ -85735,63 +86579,63 @@ function normalizeRunOptions(options) {
|
|
|
85735
86579
|
/**
|
|
85736
86580
|
* Runs the optional pre-coding verification and, when requested, its one repair prompt.
|
|
85737
86581
|
*/
|
|
85738
|
-
async function
|
|
85739
|
-
var _a, _b
|
|
86582
|
+
async function runCheckBeforeIfNeeded(options) {
|
|
86583
|
+
var _a, _b;
|
|
85740
86584
|
const { options: runOptions, runner, runnerMetadata, resolvedCoderContext, resolvedAgentSystemMessage, isRichUiEnabled, progressDisplay, uiHandle, waitForRequestedPause, hasWaitedForStart, isContinuingInterruptedPrompt, } = options;
|
|
85741
|
-
if (runOptions.
|
|
86585
|
+
if (runOptions.checkBefore === 'no') {
|
|
85742
86586
|
return hasWaitedForStart;
|
|
85743
86587
|
}
|
|
85744
|
-
if (!runOptions.
|
|
86588
|
+
if (!runOptions.checkCommand) {
|
|
85745
86589
|
throw new NotAllowed(spaceTrim$1(`
|
|
85746
|
-
${'`--
|
|
86590
|
+
${'`--check-before ' + runOptions.checkBefore + '`'} requires a verification command.
|
|
85747
86591
|
|
|
85748
|
-
Pass one with ${'`--
|
|
86592
|
+
Pass one with ${'`--check <check-command>`'} or use the default ${'`npm run check`'} command.
|
|
85749
86593
|
`));
|
|
85750
86594
|
}
|
|
85751
86595
|
if (isCleanWorkingTreeRequired(runOptions.gitChanges, isContinuingInterruptedPrompt)) {
|
|
85752
86596
|
await waitForRequestedPause({
|
|
85753
|
-
checkpointLabel: 'checking the git working tree before
|
|
86597
|
+
checkpointLabel: 'checking the git working tree before checking',
|
|
85754
86598
|
phase: 'loading',
|
|
85755
|
-
statusMessage: 'Checking the working tree before
|
|
86599
|
+
statusMessage: 'Checking the working tree before checking...',
|
|
85756
86600
|
});
|
|
85757
|
-
await ensureWorkingTreeClean((_a = runOptions.workspace) === null || _a === void 0 ? void 0 : _a.repositoryRoot);
|
|
86601
|
+
await ensureWorkingTreeClean((_b = (_a = runOptions.workspace) === null || _a === void 0 ? void 0 : _a.repositoryRoot) !== null && _b !== void 0 ? _b : runOptions.projectPath);
|
|
85758
86602
|
}
|
|
85759
|
-
const
|
|
86603
|
+
const checkBeforeCommitScope = await captureCheckBeforeCommitScopeIfNeeded(runOptions);
|
|
85760
86604
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
85761
|
-
const
|
|
85762
|
-
|
|
85763
|
-
projectPath:
|
|
86605
|
+
const checkBeforeResult = await runCheckBefore({
|
|
86606
|
+
checkCommand: runOptions.checkCommand,
|
|
86607
|
+
projectPath: runOptions.projectPath,
|
|
85764
86608
|
waitForPauseCheckpoint: waitForRequestedPause,
|
|
85765
86609
|
}).finally(() => {
|
|
85766
86610
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
85767
86611
|
});
|
|
85768
|
-
await
|
|
86612
|
+
await commitCheckBeforeChangesIfNeeded({
|
|
85769
86613
|
runOptions,
|
|
85770
|
-
|
|
86614
|
+
checkBeforeCommitScope,
|
|
85771
86615
|
waitForRequestedPause,
|
|
85772
86616
|
});
|
|
85773
|
-
if (
|
|
86617
|
+
if (checkBeforeResult.isPassed) {
|
|
85774
86618
|
return hasWaitedForStart;
|
|
85775
86619
|
}
|
|
85776
|
-
const
|
|
85777
|
-
if (runOptions.
|
|
86620
|
+
const checkOutput = limitCheckOutput(checkBeforeResult.checkOutput);
|
|
86621
|
+
if (runOptions.checkBefore === 'yes-and-fail') {
|
|
85778
86622
|
throw new NotAllowed(spaceTrim$1((block) => `
|
|
85779
|
-
Pre-coding
|
|
86623
|
+
Pre-coding check command \`${runOptions.checkCommand}\` failed.
|
|
85780
86624
|
|
|
85781
86625
|
The coding agent was not started because the project was already failing before the first queued prompt.
|
|
85782
86626
|
|
|
85783
|
-
###
|
|
86627
|
+
### Check results
|
|
85784
86628
|
${'```'}
|
|
85785
|
-
${block(
|
|
86629
|
+
${block(checkOutput)}
|
|
85786
86630
|
${'```'}
|
|
85787
86631
|
`));
|
|
85788
86632
|
}
|
|
85789
|
-
const repairPrompt = await
|
|
85790
|
-
projectPath:
|
|
85791
|
-
|
|
85792
|
-
|
|
86633
|
+
const repairPrompt = await createCheckBeforeRepairPrompt({
|
|
86634
|
+
projectPath: runOptions.projectPath,
|
|
86635
|
+
checkCommand: runOptions.checkCommand,
|
|
86636
|
+
checkOutput,
|
|
85793
86637
|
});
|
|
85794
|
-
const repairPromptLabel = buildPromptLabelForDisplay(repairPrompt.file, repairPrompt.section);
|
|
86638
|
+
const repairPromptLabel = buildPromptLabelForDisplay(repairPrompt.file, repairPrompt.section, runOptions.projectPath);
|
|
85795
86639
|
const updatedHasWaitedForStart = await waitForPromptConfirmationIfNeeded({
|
|
85796
86640
|
options: runOptions,
|
|
85797
86641
|
nextPrompt: repairPrompt,
|
|
@@ -85819,36 +86663,36 @@ async function runTestBeforeIfNeeded(options) {
|
|
|
85819
86663
|
return updatedHasWaitedForStart;
|
|
85820
86664
|
}
|
|
85821
86665
|
/**
|
|
85822
|
-
* Captures the files present before a `yes-and-fix` pre-coding
|
|
86666
|
+
* Captures the files present before a `yes-and-fix` pre-coding check, so only changes made by that check can be committed.
|
|
85823
86667
|
*/
|
|
85824
|
-
async function
|
|
86668
|
+
async function captureCheckBeforeCommitScopeIfNeeded(runOptions) {
|
|
85825
86669
|
var _a;
|
|
85826
|
-
if (runOptions.
|
|
86670
|
+
if (runOptions.checkBefore !== 'yes-and-fix' || runOptions.noCommit) {
|
|
85827
86671
|
return undefined;
|
|
85828
86672
|
}
|
|
85829
|
-
return captureCoderCommitScope((_a = runOptions.workspace) !== null && _a !== void 0 ? _a :
|
|
86673
|
+
return captureCoderCommitScope((_a = runOptions.workspace) !== null && _a !== void 0 ? _a : runOptions.projectPath);
|
|
85830
86674
|
}
|
|
85831
86675
|
/**
|
|
85832
|
-
* Commits files changed by a `yes-and-fix` pre-coding
|
|
86676
|
+
* Commits files changed by a `yes-and-fix` pre-coding check before the coder continues to a queued or repair prompt.
|
|
85833
86677
|
*/
|
|
85834
|
-
async function
|
|
86678
|
+
async function commitCheckBeforeChangesIfNeeded(options) {
|
|
85835
86679
|
var _a;
|
|
85836
|
-
const { runOptions,
|
|
85837
|
-
if (!
|
|
86680
|
+
const { runOptions, checkBeforeCommitScope, waitForRequestedPause } = options;
|
|
86681
|
+
if (!checkBeforeCommitScope) {
|
|
85838
86682
|
return;
|
|
85839
86683
|
}
|
|
85840
|
-
const relevantPaths = await resolveCoderCommitScopePaths(
|
|
86684
|
+
const relevantPaths = await resolveCoderCommitScopePaths(checkBeforeCommitScope);
|
|
85841
86685
|
if (relevantPaths.length === 0) {
|
|
85842
86686
|
return;
|
|
85843
86687
|
}
|
|
85844
86688
|
await waitForRequestedPause({
|
|
85845
|
-
checkpointLabel: 'committing changes made by pre-coding
|
|
86689
|
+
checkpointLabel: 'committing changes made by pre-coding checks',
|
|
85846
86690
|
phase: 'verifying',
|
|
85847
|
-
statusMessage: 'Committing changes made by pre-coding
|
|
86691
|
+
statusMessage: 'Committing changes made by pre-coding checks...',
|
|
85848
86692
|
});
|
|
85849
|
-
await commitChanges(
|
|
86693
|
+
await commitChanges(PRE_CODING_CHECK_CHANGES_COMMIT_MESSAGE, {
|
|
85850
86694
|
autoPush: runOptions.autoPush,
|
|
85851
|
-
projectPath: (_a =
|
|
86695
|
+
projectPath: (_a = checkBeforeCommitScope.repositoryRoot) !== null && _a !== void 0 ? _a : checkBeforeCommitScope.projectPath,
|
|
85852
86696
|
relevantPaths,
|
|
85853
86697
|
});
|
|
85854
86698
|
}
|
|
@@ -85894,7 +86738,6 @@ function startPauseListenerIfNeeded(isRichUiEnabled) {
|
|
|
85894
86738
|
* Runs the dry-run reporting mode and returns whether the main execution should stop.
|
|
85895
86739
|
*/
|
|
85896
86740
|
async function runDryRunIfRequested(options, agentReferences) {
|
|
85897
|
-
var _a, _b;
|
|
85898
86741
|
if (!options.dryRun) {
|
|
85899
86742
|
return false;
|
|
85900
86743
|
}
|
|
@@ -85903,7 +86746,7 @@ async function runDryRunIfRequested(options, agentReferences) {
|
|
|
85903
86746
|
modelName: options.agentName ? resolveRunnerModel(options.agentName, options.model) : options.model,
|
|
85904
86747
|
agentReferences,
|
|
85905
86748
|
};
|
|
85906
|
-
const promptFiles = (await loadPromptFiles(join(
|
|
86749
|
+
const promptFiles = (await loadPromptFiles(join(options.projectPath, 'prompts'), {
|
|
85907
86750
|
isMissingDirectoryAllowed: true,
|
|
85908
86751
|
})).map((file) => ({
|
|
85909
86752
|
...file,
|
|
@@ -85912,7 +86755,7 @@ async function runDryRunIfRequested(options, agentReferences) {
|
|
|
85912
86755
|
const stats = summarizePrompts(promptFiles, options.priorityFilter);
|
|
85913
86756
|
printStats(stats, options.priorityFilter);
|
|
85914
86757
|
console.info(colors.yellow('Following prompts need to be written:'));
|
|
85915
|
-
printPromptsToBeWritten(promptFiles, options.priorityFilter);
|
|
86758
|
+
printPromptsToBeWritten(promptFiles, options.priorityFilter, options.projectPath);
|
|
85916
86759
|
return true;
|
|
85917
86760
|
}
|
|
85918
86761
|
/**
|
|
@@ -85927,7 +86770,7 @@ function initializeRunUi(uiHandle, runnerName, actualRunnerModel, options) {
|
|
|
85927
86770
|
serverUrl: options.serverUrl,
|
|
85928
86771
|
priorityFilter: options.priorityFilter,
|
|
85929
86772
|
limit: options.limit,
|
|
85930
|
-
|
|
86773
|
+
checkCommand: options.checkCommand,
|
|
85931
86774
|
});
|
|
85932
86775
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setPhase('loading');
|
|
85933
86776
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setStatusMessage(`Running prompts with ${runnerName}`);
|
|
@@ -85950,10 +86793,9 @@ async function initializeRunUiAgentVisual(uiHandle, agentSource) {
|
|
|
85950
86793
|
* Loads prompt files, updates progress displays, and selects the next runnable prompt.
|
|
85951
86794
|
*/
|
|
85952
86795
|
async function loadPromptQueueSnapshot(options) {
|
|
85953
|
-
var _a, _b;
|
|
85954
86796
|
const { options: runOptions, isRichUiEnabled, progressDisplay, uiHandle, promptRunnerIdentity, isContinuingInterruptedPrompt, } = options;
|
|
85955
86797
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentScriptPath(undefined);
|
|
85956
|
-
const promptFiles = await loadPromptFiles(join(
|
|
86798
|
+
const promptFiles = await loadPromptFiles(join(runOptions.projectPath, 'prompts'));
|
|
85957
86799
|
const stats = summarizePrompts(promptFiles, runOptions.priorityFilter);
|
|
85958
86800
|
progressDisplay === null || progressDisplay === void 0 ? void 0 : progressDisplay.update(stats);
|
|
85959
86801
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.updateProgress(stats);
|
|
@@ -85980,10 +86822,10 @@ function showUpcomingTasksOnce(options) {
|
|
|
85980
86822
|
}
|
|
85981
86823
|
if (stats.toBeWritten > 0) {
|
|
85982
86824
|
console.info(colors.yellow('Following prompts need to be written:'));
|
|
85983
|
-
printPromptsToBeWritten(promptFiles, priorityFilter);
|
|
86825
|
+
printPromptsToBeWritten(promptFiles, priorityFilter, options.projectPath);
|
|
85984
86826
|
console.info('');
|
|
85985
86827
|
}
|
|
85986
|
-
printUpcomingTasks(listUpcomingTasks(promptFiles, priorityFilter, promptRunnerIdentity));
|
|
86828
|
+
printUpcomingTasks(listUpcomingTasks(promptFiles, priorityFilter, promptRunnerIdentity, options.projectPath));
|
|
85987
86829
|
return true;
|
|
85988
86830
|
}
|
|
85989
86831
|
/**
|
|
@@ -86180,12 +87022,14 @@ function buildCoderServerPromptFileResponses(options) {
|
|
|
86180
87022
|
return [
|
|
86181
87023
|
...options.promptFiles.map((promptFile) => buildCoderServerPromptFileResponse({
|
|
86182
87024
|
promptFile,
|
|
87025
|
+
projectPath: options.projectPath,
|
|
86183
87026
|
isFinished: false,
|
|
86184
87027
|
priorityFilter: options.priorityFilter,
|
|
86185
87028
|
activePrompt,
|
|
86186
87029
|
})),
|
|
86187
87030
|
...options.finishedPromptFiles.map((promptFile) => buildCoderServerPromptFileResponse({
|
|
86188
87031
|
promptFile,
|
|
87032
|
+
projectPath: options.projectPath,
|
|
86189
87033
|
isFinished: true,
|
|
86190
87034
|
priorityFilter: options.priorityFilter,
|
|
86191
87035
|
activePrompt,
|
|
@@ -86196,13 +87040,15 @@ function buildCoderServerPromptFileResponses(options) {
|
|
|
86196
87040
|
* Builds one prompt-file response.
|
|
86197
87041
|
*/
|
|
86198
87042
|
function buildCoderServerPromptFileResponse(options) {
|
|
87043
|
+
var _a;
|
|
86199
87044
|
const { promptFile, isFinished, priorityFilter, activePrompt } = options;
|
|
86200
87045
|
return {
|
|
86201
87046
|
filePath: promptFile.path,
|
|
86202
87047
|
fileName: promptFile.name,
|
|
86203
|
-
relativeFilePath: relative(process.cwd(), promptFile.path).replace(/\\/gu, '/'),
|
|
87048
|
+
relativeFilePath: relative((_a = options.projectPath) !== null && _a !== void 0 ? _a : process.cwd(), promptFile.path).replace(/\\/gu, '/'),
|
|
86204
87049
|
isFinished,
|
|
86205
87050
|
sections: promptFile.sections.map((section) => buildCoderServerPromptSectionResponse({
|
|
87051
|
+
projectPath: options.projectPath,
|
|
86206
87052
|
promptFile,
|
|
86207
87053
|
section,
|
|
86208
87054
|
isFinished,
|
|
@@ -86217,7 +87063,7 @@ function buildCoderServerPromptFileResponse(options) {
|
|
|
86217
87063
|
function buildCoderServerPromptSectionResponse(options) {
|
|
86218
87064
|
const { promptFile, section, isFinished, priorityFilter, activePrompt } = options;
|
|
86219
87065
|
const isUnwritten = isPromptToBeWritten(promptFile, section);
|
|
86220
|
-
const isActive = isPromptActive(promptFile, section, activePrompt);
|
|
87066
|
+
const isActive = isPromptActive(promptFile, section, activePrompt, options.projectPath);
|
|
86221
87067
|
const column = getPromptColumn({
|
|
86222
87068
|
section,
|
|
86223
87069
|
isFinished,
|
|
@@ -86232,7 +87078,7 @@ function buildCoderServerPromptSectionResponse(options) {
|
|
|
86232
87078
|
priority: section.priority,
|
|
86233
87079
|
summary: buildPromptSummary(promptFile, section),
|
|
86234
87080
|
content: buildCodexPrompt(promptFile, section),
|
|
86235
|
-
label: buildPromptLabelForDisplay(promptFile, section),
|
|
87081
|
+
label: buildPromptLabelForDisplay(promptFile, section, options.projectPath),
|
|
86236
87082
|
tags: buildPromptTags({
|
|
86237
87083
|
section,
|
|
86238
87084
|
isUnwritten,
|
|
@@ -86309,11 +87155,11 @@ function getActivePrompt(uiState) {
|
|
|
86309
87155
|
/**
|
|
86310
87156
|
* Checks whether a parsed section is the prompt currently handled by the active agent.
|
|
86311
87157
|
*/
|
|
86312
|
-
function isPromptActive(promptFile, section, activePrompt) {
|
|
87158
|
+
function isPromptActive(promptFile, section, activePrompt, projectPath) {
|
|
86313
87159
|
if (!activePrompt || (section.status !== 'todo' && section.status !== 'in-progress')) {
|
|
86314
87160
|
return false;
|
|
86315
87161
|
}
|
|
86316
|
-
return buildPromptLabelForDisplay(promptFile, section) === activePrompt.label;
|
|
87162
|
+
return buildPromptLabelForDisplay(promptFile, section, projectPath) === activePrompt.label;
|
|
86317
87163
|
}
|
|
86318
87164
|
// Note: [🟡] Code for CLI command [coder server](scripts/run-codex-prompts/server/buildCoderServerPromptResponse.ts) should never be published outside of `@promptbook/cli`
|
|
86319
87165
|
|
|
@@ -87234,6 +88080,7 @@ async function loadPromptsForApi(options) {
|
|
|
87234
88080
|
const promptFiles = await loadPromptFilesSafely(promptsDir);
|
|
87235
88081
|
const finishedPromptFiles = await loadPromptFilesSafely(join(promptsDir, FINISHED_PROMPTS_DIRECTORY_NAME));
|
|
87236
88082
|
return buildCoderServerPromptFileResponses({
|
|
88083
|
+
projectPath: dirname(promptsDir),
|
|
87237
88084
|
promptFiles,
|
|
87238
88085
|
finishedPromptFiles,
|
|
87239
88086
|
priorityFilter,
|
|
@@ -87320,18 +88167,20 @@ function jsonHeaders() {
|
|
|
87320
88167
|
* @private internal function of `ptbk coder server`
|
|
87321
88168
|
*/
|
|
87322
88169
|
async function runCodexPromptsServer(options) {
|
|
87323
|
-
var _a, _b, _c, _d;
|
|
87324
|
-
const { port, ...
|
|
87325
|
-
if (
|
|
87326
|
-
await runCodexPrompts(
|
|
88170
|
+
var _a, _b, _c, _d, _e;
|
|
88171
|
+
const { port, ...providedOptions } = options;
|
|
88172
|
+
if (providedOptions.dryRun) {
|
|
88173
|
+
await runCodexPrompts(providedOptions);
|
|
87327
88174
|
return;
|
|
87328
88175
|
}
|
|
88176
|
+
const workspace = (_a = providedOptions.workspace) !== null && _a !== void 0 ? _a : await $resolveWorkspaceRepository(providedOptions.projectPath);
|
|
88177
|
+
const runOptions = { ...providedOptions, workspace, projectPath: workspace.projectPath };
|
|
87329
88178
|
const serverUrl = `http://localhost:${port}`;
|
|
87330
88179
|
const uiState = new CoderRunUiState(moment());
|
|
87331
88180
|
const priorityFilter = normalizePriorityFilter({
|
|
87332
88181
|
priority: runOptions.priority,
|
|
87333
|
-
minimumPriority: (
|
|
87334
|
-
maximumPriority: (
|
|
88182
|
+
minimumPriority: (_b = runOptions.minimumPriority) !== null && _b !== void 0 ? _b : (_c = runOptions.priorityFilter) === null || _c === void 0 ? void 0 : _c.minimumPriority,
|
|
88183
|
+
maximumPriority: (_d = runOptions.maximumPriority) !== null && _d !== void 0 ? _d : (_e = runOptions.priorityFilter) === null || _e === void 0 ? void 0 : _e.maximumPriority,
|
|
87335
88184
|
});
|
|
87336
88185
|
const serverHandle = startCoderHttpServer({
|
|
87337
88186
|
port,
|