@promptbook/node 0.114.0-11 → 0.114.0-13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.es.js +459 -133
- package/esm/index.es.js.map +1 -1
- package/esm/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +22 -4
- package/esm/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +3 -3
- package/esm/scripts/run-codex-prompts/common/runGoScript/$spawnLoggedBashScript.d.ts +25 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/$terminateLoggedBashProcessTree.d.ts +11 -0
- package/esm/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +4 -0
- package/esm/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +5 -0
- package/esm/src/book-2.0/agent-source/ParsedUnknownCommitment.d.ts +26 -0
- package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.unknown.test.d.ts +1 -0
- package/esm/src/book-2.0/agent-source/getBookCommitmentLineType.d.ts +19 -0
- package/esm/src/book-2.0/agent-source/parseAgentSourceWithCommitments.unknown.test.d.ts +1 -0
- package/esm/src/book-3.0/AgentMessageRunReport.d.ts +28 -0
- package/esm/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +94 -0
- package/esm/src/book-3.0/AgentPlannedMessagesSidecar.test.d.ts +1 -0
- package/esm/src/book-3.0/createAgentMessageSidecarBaseName.d.ts +13 -0
- package/esm/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.d.ts +28 -0
- package/esm/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.test.d.ts +1 -0
- package/esm/src/book-components/Chat/utils/agentProjectToolCall.d.ts +46 -0
- package/esm/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +24 -0
- package/esm/src/cli/cli-commands/common/harness/$checkHarnessInstallation.d.ts +3 -3
- package/esm/src/cli/cli-commands/common/harness/$checkHarnessInstallation.test.d.ts +1 -0
- package/esm/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +3 -3
- package/esm/src/cli/cli-commands/common/harness/HarnessInstallationStatus.d.ts +3 -2
- package/esm/src/cli/cli-commands/common/harnessUpdateCliOptions.d.ts +29 -0
- package/esm/src/cli/cli-commands/common/harnessUpdateCliOptions.test.d.ts +1 -0
- package/esm/src/executables/platforms/locateAppOnWindows.d.ts +1 -1
- package/esm/src/executables/platforms/locateAppOnWindows.test.d.ts +1 -0
- package/esm/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +59 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.d.ts +19 -0
- package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.test.d.ts +1 -0
- package/esm/src/version.d.ts +1 -1
- package/package.json +2 -2
- package/umd/index.umd.js +457 -131
- package/umd/index.umd.js.map +1 -1
- package/umd/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +22 -4
- package/umd/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +3 -3
- package/umd/scripts/run-codex-prompts/common/runGoScript/$spawnLoggedBashScript.d.ts +25 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/$terminateLoggedBashProcessTree.d.ts +11 -0
- package/umd/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +4 -0
- package/umd/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +5 -0
- package/umd/src/book-2.0/agent-source/ParsedUnknownCommitment.d.ts +26 -0
- package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.unknown.test.d.ts +1 -0
- package/umd/src/book-2.0/agent-source/getBookCommitmentLineType.d.ts +19 -0
- package/umd/src/book-2.0/agent-source/parseAgentSourceWithCommitments.unknown.test.d.ts +1 -0
- package/umd/src/book-3.0/AgentMessageRunReport.d.ts +28 -0
- package/umd/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +94 -0
- package/umd/src/book-3.0/AgentPlannedMessagesSidecar.test.d.ts +1 -0
- package/umd/src/book-3.0/createAgentMessageSidecarBaseName.d.ts +13 -0
- package/umd/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.d.ts +28 -0
- package/umd/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.test.d.ts +1 -0
- package/umd/src/book-components/Chat/utils/agentProjectToolCall.d.ts +46 -0
- package/umd/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +24 -0
- package/umd/src/cli/cli-commands/common/harness/$checkHarnessInstallation.d.ts +3 -3
- package/umd/src/cli/cli-commands/common/harness/$checkHarnessInstallation.test.d.ts +1 -0
- package/umd/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +3 -3
- package/umd/src/cli/cli-commands/common/harness/HarnessInstallationStatus.d.ts +3 -2
- package/umd/src/cli/cli-commands/common/harnessUpdateCliOptions.d.ts +29 -0
- package/umd/src/cli/cli-commands/common/harnessUpdateCliOptions.test.d.ts +1 -0
- package/umd/src/executables/platforms/locateAppOnWindows.d.ts +1 -1
- package/umd/src/executables/platforms/locateAppOnWindows.test.d.ts +1 -0
- package/umd/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +59 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.d.ts +19 -0
- package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.test.d.ts +1 -0
- package/umd/src/version.d.ts +1 -1
- package/esm/apps/agents-server/src/utils/agentGoalChat/agentGoalChatConstants.d.ts +0 -12
- package/esm/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeConstants.d.ts +0 -40
- package/umd/apps/agents-server/src/utils/agentGoalChat/agentGoalChatConstants.d.ts +0 -12
- package/umd/apps/agents-server/src/utils/agentProjects/agentProjectRuntimeConstants.d.ts +0 -40
package/esm/index.es.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { join, dirname, basename, isAbsolute, resolve, relative } from 'path';
|
|
1
|
+
import { join, dirname, basename, isAbsolute, resolve, delimiter, relative } from 'path';
|
|
2
2
|
import { unlink, mkdir, appendFile, writeFile, readFile, stat, access, constants, readdir, watch } from 'fs/promises';
|
|
3
3
|
import _spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
|
|
4
4
|
import colors from 'colors';
|
|
5
|
-
import { spawn } from 'child_process';
|
|
5
|
+
import { spawn, spawnSync } from 'child_process';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
7
|
import CryptoJS from 'crypto-js';
|
|
8
8
|
import hexEncoder from 'crypto-js/enc-hex';
|
|
@@ -29,7 +29,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
|
|
|
29
29
|
* @generated
|
|
30
30
|
* @see https://github.com/webgptorg/promptbook
|
|
31
31
|
*/
|
|
32
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
32
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-13';
|
|
33
33
|
/**
|
|
34
34
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
35
35
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -2936,14 +2936,90 @@ const PTBK_CODER_LOG_FILE_ENV_NAME = 'PTBK_CODER_LOG_FILE';
|
|
|
2936
2936
|
* without the generated script and the prompt it embeds.
|
|
2937
2937
|
*/
|
|
2938
2938
|
const SCRIPT_EXECUTION_LOG_RAW_OUTPUT_MARKER = '--- raw output ---';
|
|
2939
|
+
/**
|
|
2940
|
+
* Command which terminates the Bash process tree rooted at the running harness.
|
|
2941
|
+
*
|
|
2942
|
+
* Bash's POSIX process IDs differ from Windows process IDs in Git Bash, so the Windows branch resolves the native PID
|
|
2943
|
+
* before delegating to `taskkill`. Unix harnesses run in a dedicated Bash job process group, which can be terminated
|
|
2944
|
+
* with its negative process ID.
|
|
2945
|
+
*/
|
|
2946
|
+
const TERMINATE_BASH_PROCESS_TREE_COMMAND = process.platform === 'win32'
|
|
2947
|
+
? spaceTrim$1(`
|
|
2948
|
+
HARNESS_WINDOWS_PROCESS_ID="$(ps -l -p "$HARNESS_PROCESS_ID" | awk 'NR == 2 { print $4 }')"
|
|
2949
|
+
if [ -n "$HARNESS_WINDOWS_PROCESS_ID" ]; then
|
|
2950
|
+
MSYS_NO_PATHCONV=1 taskkill.exe /PID "$HARNESS_WINDOWS_PROCESS_ID" /T /F > /dev/null 2>&1 || true
|
|
2951
|
+
fi
|
|
2952
|
+
`)
|
|
2953
|
+
: 'kill -TERM -- "-$HARNESS_PROCESS_ID" 2>/dev/null || true';
|
|
2954
|
+
/**
|
|
2955
|
+
* Shell condition that detects whether the Node process which owns the harness is still running.
|
|
2956
|
+
*
|
|
2957
|
+
* Git Bash translates process IDs and command switches, so querying the native Windows PID needs both `tasklist` and
|
|
2958
|
+
* disabled MSYS path conversion there. Unix can use the native `kill -0` process existence check.
|
|
2959
|
+
*/
|
|
2960
|
+
const IS_PARENT_PROCESS_RUNNING_CONDITION = process.platform === 'win32'
|
|
2961
|
+
? 'MSYS_NO_PATHCONV=1 tasklist.exe /FI "PID eq $PARENT_CODER_PROCESS_ID" /NH | awk -v processId="$PARENT_CODER_PROCESS_ID" \'$2 == processId { isFound = 1 } END { exit isFound ? 0 : 1 }\''
|
|
2962
|
+
: 'kill -0 "$PARENT_CODER_PROCESS_ID" 2>/dev/null';
|
|
2963
|
+
/**
|
|
2964
|
+
* Environment variable that identifies the Node process responsible for a temporary harness shell.
|
|
2965
|
+
*/
|
|
2966
|
+
const PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME = 'PTBK_CODER_PARENT_PROCESS_ID';
|
|
2939
2967
|
/**
|
|
2940
2968
|
* Small bash wrapper that preserves stdout/stderr streams while teeing both into the runtime log file.
|
|
2969
|
+
*
|
|
2970
|
+
* A watcher polls the owning Node process by its PID. If that process exits abruptly, the watcher stops the whole
|
|
2971
|
+
* Bash and harness process tree instead of letting it continue as an orphan.
|
|
2941
2972
|
*/
|
|
2942
2973
|
const LOGGED_BASH_WRAPPER_COMMAND = spaceTrim$1(`
|
|
2974
|
+
PARENT_CODER_PROCESS_ID="\${${PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME}}"
|
|
2975
|
+
unset ${PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME}
|
|
2976
|
+
|
|
2977
|
+
terminate_harness_process_tree() {
|
|
2978
|
+
# Keep the EXIT cleanup intact so the wrapper can also stop its parent-process watcher.
|
|
2979
|
+
trap - HUP INT TERM
|
|
2980
|
+
${TERMINATE_BASH_PROCESS_TREE_COMMAND}
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
is_parent_process_running() {
|
|
2984
|
+
${IS_PARENT_PROCESS_RUNNING_CONDITION}
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2943
2987
|
if [ -n "\${${PTBK_CODER_LOG_FILE_ENV_NAME}:-}" ]; then
|
|
2944
|
-
exec > >(tee -a "
|
|
2988
|
+
exec > >(tee -a "$${PTBK_CODER_LOG_FILE_ENV_NAME}") 2> >(tee -a "$${PTBK_CODER_LOG_FILE_ENV_NAME}" >&2)
|
|
2989
|
+
fi
|
|
2990
|
+
|
|
2991
|
+
watch_parent_process() {
|
|
2992
|
+
trap 'exit 0' HUP INT TERM
|
|
2993
|
+
|
|
2994
|
+
while is_parent_process_running; do
|
|
2995
|
+
sleep 1
|
|
2996
|
+
done
|
|
2997
|
+
|
|
2998
|
+
terminate_harness_process_tree
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
# Background harness jobs need their own process group on Unix so termination cannot reach the parent coder.
|
|
3002
|
+
set -m
|
|
3003
|
+
if ! is_parent_process_running; then
|
|
3004
|
+
exit 1
|
|
2945
3005
|
fi
|
|
2946
|
-
bash "$1"
|
|
3006
|
+
bash "$1" &
|
|
3007
|
+
HARNESS_PROCESS_ID=$!
|
|
3008
|
+
|
|
3009
|
+
cleanup_parent_process_watcher() {
|
|
3010
|
+
kill "$PARENT_PROCESS_WATCHER_PID" 2>/dev/null || true
|
|
3011
|
+
wait "$PARENT_PROCESS_WATCHER_PID" 2>/dev/null || true
|
|
3012
|
+
}
|
|
3013
|
+
|
|
3014
|
+
watch_parent_process &
|
|
3015
|
+
PARENT_PROCESS_WATCHER_PID=$!
|
|
3016
|
+
|
|
3017
|
+
trap cleanup_parent_process_watcher EXIT
|
|
3018
|
+
trap terminate_harness_process_tree HUP INT TERM
|
|
3019
|
+
|
|
3020
|
+
wait "$HARNESS_PROCESS_ID"
|
|
3021
|
+
SCRIPT_EXIT_CODE=$?
|
|
3022
|
+
exit "$SCRIPT_EXIT_CODE"
|
|
2947
3023
|
`);
|
|
2948
3024
|
/**
|
|
2949
3025
|
* Shapes one bash invocation that optionally mirrors live script output into a temporary log file.
|
|
@@ -2999,6 +3075,38 @@ function describeTempScriptKind(scriptPath) {
|
|
|
2999
3075
|
return scriptPath.toLowerCase().endsWith('.test.sh') ? 'test shell' : 'runner shell';
|
|
3000
3076
|
}
|
|
3001
3077
|
|
|
3078
|
+
/**
|
|
3079
|
+
* Standard streams used by every temporary Bash runner.
|
|
3080
|
+
*/
|
|
3081
|
+
const BASH_PROCESS_STDIO = ['pipe', 'pipe', 'pipe'];
|
|
3082
|
+
/**
|
|
3083
|
+
* Whether the current Node process is running on Windows.
|
|
3084
|
+
*/
|
|
3085
|
+
const IS_WINDOWS$1 = process.platform === 'win32';
|
|
3086
|
+
/**
|
|
3087
|
+
* Starts one temporary Bash script in a process tree owned by the current Node process.
|
|
3088
|
+
*
|
|
3089
|
+
* The wrapper watches the supplied owning process ID. When that process exits abruptly, the wrapper terminates every
|
|
3090
|
+
* nested shell and harness process instead of leaving it orphaned.
|
|
3091
|
+
*
|
|
3092
|
+
* @private internal utility of the coding prompt runner
|
|
3093
|
+
*/
|
|
3094
|
+
function $spawnLoggedBashScript(options) {
|
|
3095
|
+
var _a;
|
|
3096
|
+
const bashExecution = buildLoggedBashExecution(options.scriptPath, options.logPath);
|
|
3097
|
+
const parentProcessId = (_a = options.parentProcessId) !== null && _a !== void 0 ? _a : process.pid;
|
|
3098
|
+
return spawn('bash', bashExecution.args, {
|
|
3099
|
+
detached: !IS_WINDOWS$1,
|
|
3100
|
+
env: {
|
|
3101
|
+
...process.env,
|
|
3102
|
+
...bashExecution.env,
|
|
3103
|
+
[PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME]: parentProcessId.toString(),
|
|
3104
|
+
},
|
|
3105
|
+
stdio: BASH_PROCESS_STDIO,
|
|
3106
|
+
windowsHide: true,
|
|
3107
|
+
});
|
|
3108
|
+
}
|
|
3109
|
+
|
|
3002
3110
|
/**
|
|
3003
3111
|
* Prints one live shell output chunk to the terminal when console mirroring is enabled.
|
|
3004
3112
|
*/
|
|
@@ -3021,12 +3129,12 @@ function printLiveScriptChunk(chunk, source, shouldPrintLiveOutput) {
|
|
|
3021
3129
|
async function runBashScriptWithOutput(options) {
|
|
3022
3130
|
var _a;
|
|
3023
3131
|
await appendScriptExecutionLogStart(options);
|
|
3024
|
-
const bashExecution = buildLoggedBashExecution(options.scriptPath, options.logPath);
|
|
3025
3132
|
const scriptPathPosix = toPosixPath(options.scriptPath);
|
|
3026
3133
|
const shouldPrintLiveOutput = (_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true;
|
|
3027
3134
|
return await new Promise((resolve, reject) => {
|
|
3028
|
-
const commandProcess =
|
|
3029
|
-
|
|
3135
|
+
const commandProcess = $spawnLoggedBashScript({
|
|
3136
|
+
scriptPath: options.scriptPath,
|
|
3137
|
+
logPath: options.logPath,
|
|
3030
3138
|
});
|
|
3031
3139
|
let output = '';
|
|
3032
3140
|
let settled = false;
|
|
@@ -3085,8 +3193,9 @@ async function runBashScriptWithOutput(options) {
|
|
|
3085
3193
|
const failure = new Error(spaceTrim$1(output) || `Command "bash ${scriptPathPosix}" exited with code ${code}`);
|
|
3086
3194
|
settleWithLog(`failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}`, () => reject(failure), failure);
|
|
3087
3195
|
};
|
|
3196
|
+
// Wait for `close`, not only `exit`, because the Bash wrapper can still be flushing its tee process
|
|
3197
|
+
// substitutions after the direct shell exits.
|
|
3088
3198
|
commandProcess.on('close', handleExit);
|
|
3089
|
-
commandProcess.on('exit', handleExit);
|
|
3090
3199
|
commandProcess.on('disconnect', () => {
|
|
3091
3200
|
const failure = new Error(`Command "bash ${scriptPathPosix}" disconnected`);
|
|
3092
3201
|
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
@@ -3953,6 +4062,35 @@ function isGitHubCopilotArgumentLimitError(error) {
|
|
|
3953
4062
|
error.message.includes('bin/node'));
|
|
3954
4063
|
}
|
|
3955
4064
|
|
|
4065
|
+
/**
|
|
4066
|
+
* Whether the current coder process runs on Windows.
|
|
4067
|
+
*/
|
|
4068
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
4069
|
+
/**
|
|
4070
|
+
* Stops one active temporary Bash shell together with the harness process tree it owns.
|
|
4071
|
+
*
|
|
4072
|
+
* Unix sends `SIGTERM` to the wrapper so its shell trap terminates the separately grouped harness job. Windows does
|
|
4073
|
+
* not reliably deliver that signal to Bash, so the native `taskkill` command terminates the direct shell tree instead.
|
|
4074
|
+
*
|
|
4075
|
+
* @private internal utility of the coding prompt runner
|
|
4076
|
+
*/
|
|
4077
|
+
function $terminateLoggedBashProcessTree(commandProcess) {
|
|
4078
|
+
if (commandProcess.exitCode !== null || commandProcess.signalCode !== null) {
|
|
4079
|
+
return;
|
|
4080
|
+
}
|
|
4081
|
+
if (!IS_WINDOWS) {
|
|
4082
|
+
commandProcess.kill('SIGTERM');
|
|
4083
|
+
return;
|
|
4084
|
+
}
|
|
4085
|
+
if (!commandProcess.pid) {
|
|
4086
|
+
return;
|
|
4087
|
+
}
|
|
4088
|
+
spawnSync('taskkill.exe', ['/PID', commandProcess.pid.toString(), '/T', '/F'], {
|
|
4089
|
+
stdio: 'ignore',
|
|
4090
|
+
windowsHide: true,
|
|
4091
|
+
});
|
|
4092
|
+
}
|
|
4093
|
+
|
|
3956
4094
|
/**
|
|
3957
4095
|
* Maximum number of output characters included in thrown error messages.
|
|
3958
4096
|
*/
|
|
@@ -3995,15 +4133,16 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
3995
4133
|
const scriptPathPosix = toPosixPath(scriptPath);
|
|
3996
4134
|
const shouldPrintLiveOutput = (_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true;
|
|
3997
4135
|
await appendScriptExecutionLogStart(options);
|
|
3998
|
-
const bashExecution = buildLoggedBashExecution(scriptPath, options.logPath);
|
|
3999
4136
|
return await new Promise((resolve, reject) => {
|
|
4000
|
-
const commandProcess =
|
|
4001
|
-
|
|
4137
|
+
const commandProcess = $spawnLoggedBashScript({
|
|
4138
|
+
scriptPath,
|
|
4139
|
+
logPath: options.logPath,
|
|
4002
4140
|
});
|
|
4003
4141
|
let stdoutBuffer = '';
|
|
4004
4142
|
let stderrBuffer = '';
|
|
4005
4143
|
let fullOutput = '';
|
|
4006
4144
|
let markerSeen = false;
|
|
4145
|
+
let isCompletedAfterIdleTimeout = false;
|
|
4007
4146
|
let idleTimer;
|
|
4008
4147
|
let settled = false;
|
|
4009
4148
|
let isSettling = false;
|
|
@@ -4045,15 +4184,16 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
4045
4184
|
});
|
|
4046
4185
|
};
|
|
4047
4186
|
/**
|
|
4048
|
-
*
|
|
4187
|
+
* Stops a marker-completed process tree after its trailing output becomes idle.
|
|
4049
4188
|
*/
|
|
4050
4189
|
const finishAfterIdleTimeout = () => {
|
|
4051
|
-
|
|
4190
|
+
isCompletedAfterIdleTimeout = true;
|
|
4191
|
+
idleTimer = undefined;
|
|
4052
4192
|
try {
|
|
4053
|
-
commandProcess
|
|
4193
|
+
$terminateLoggedBashProcessTree(commandProcess);
|
|
4054
4194
|
}
|
|
4055
4195
|
catch (_a) {
|
|
4056
|
-
//
|
|
4196
|
+
// The close handler below still settles normally when Bash already exited before the idle timer fired.
|
|
4057
4197
|
}
|
|
4058
4198
|
};
|
|
4059
4199
|
/**
|
|
@@ -4112,7 +4252,11 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
4112
4252
|
const failure = code === 0 || markerSeen
|
|
4113
4253
|
? undefined
|
|
4114
4254
|
: new Error(buildCommandFailureMessage(scriptPathPosix, code, fullOutput));
|
|
4115
|
-
const status =
|
|
4255
|
+
const status = isCompletedAfterIdleTimeout
|
|
4256
|
+
? 'completed after idle timeout'
|
|
4257
|
+
: failure
|
|
4258
|
+
? `failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}`
|
|
4259
|
+
: 'succeeded';
|
|
4116
4260
|
settleWithLog(status, () => {
|
|
4117
4261
|
if (!failure) {
|
|
4118
4262
|
resolve(fullOutput);
|
|
@@ -4121,8 +4265,9 @@ async function runScriptUntilMarkerIdle(options) {
|
|
|
4121
4265
|
reject(failure);
|
|
4122
4266
|
});
|
|
4123
4267
|
};
|
|
4268
|
+
// Wait for `close`, not only `exit`, because the Bash wrapper can still be flushing its tee process
|
|
4269
|
+
// substitutions after the direct shell exits.
|
|
4124
4270
|
commandProcess.on('close', handleExit);
|
|
4125
|
-
commandProcess.on('exit', handleExit);
|
|
4126
4271
|
commandProcess.on('disconnect', () => {
|
|
4127
4272
|
const failure = new Error(buildCommandFailureMessage(scriptPathPosix, null, fullOutput));
|
|
4128
4273
|
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
@@ -5075,7 +5220,7 @@ function buildAgentProjectsPromptSection(options = {}) {
|
|
|
5075
5220
|
- You have 100% control over every project folder: create, read, modify, and delete files there, run scripts and commands inside it, and keep any persistent data you need between conversations.
|
|
5076
5221
|
- When the user asks you to build something (for example a website) or to do longer-term work, create a new project folder \`${AGENT_PROJECTS_DIRECTORY_PATH}/<project-name>/\` (use a short kebab-case name) and do the work inside it. Modify an existing project when the user refers to work you already did.
|
|
5077
5222
|
- A project can be a git repository — you can run \`git init\` inside a project folder and commit your work there.
|
|
5078
|
-
- Do not touch anything outside the \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory
|
|
5223
|
+
- Do not touch anything outside the \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory beyond the file changes allowed at the top of this prompt.
|
|
5079
5224
|
|
|
5080
5225
|
${block(buildProjectReferenceInstructions(projectsUrlPath))}
|
|
5081
5226
|
${block(buildProjectRuntimeInstructions(options.projectRuntimeApi))}
|
|
@@ -5131,63 +5276,148 @@ function buildProjectRuntimeInstructions(projectRuntimeApi) {
|
|
|
5131
5276
|
}
|
|
5132
5277
|
|
|
5133
5278
|
/**
|
|
5134
|
-
*
|
|
5279
|
+
* Milliseconds in one second.
|
|
5280
|
+
*
|
|
5281
|
+
* @private internal timeout-chat constant
|
|
5135
5282
|
*/
|
|
5283
|
+
const SECOND_IN_MILLISECONDS = 1000;
|
|
5136
5284
|
/**
|
|
5137
|
-
*
|
|
5285
|
+
* Seconds in one minute.
|
|
5286
|
+
*
|
|
5287
|
+
* @private internal timeout-chat constant
|
|
5138
5288
|
*/
|
|
5139
|
-
const
|
|
5140
|
-
|
|
5289
|
+
const MINUTE_IN_SECONDS = 60;
|
|
5141
5290
|
/**
|
|
5142
|
-
*
|
|
5291
|
+
* Seconds in one hour.
|
|
5292
|
+
*
|
|
5293
|
+
* @private internal timeout-chat constant
|
|
5294
|
+
*/
|
|
5295
|
+
const HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS;
|
|
5296
|
+
/**
|
|
5297
|
+
* Seconds in one day.
|
|
5298
|
+
*
|
|
5299
|
+
* @private internal timeout-chat constant
|
|
5300
|
+
*/
|
|
5301
|
+
const HOURS_IN_DAY = 24;
|
|
5302
|
+
/**
|
|
5303
|
+
* Seconds in one day.
|
|
5304
|
+
*
|
|
5305
|
+
* @private internal timeout-chat constant
|
|
5143
5306
|
*/
|
|
5307
|
+
const DAY_IN_SECONDS = HOURS_IN_DAY * HOUR_IN_SECONDS;
|
|
5144
5308
|
/**
|
|
5145
|
-
*
|
|
5309
|
+
* Converts timeout duration into natural language sentence fragments.
|
|
5310
|
+
*
|
|
5311
|
+
* Shared by every timeout surface: the chat chips, the goal-chat planned messages of the Agents
|
|
5312
|
+
* Server, and the planned-message prompt section of the agent-folder runner.
|
|
5313
|
+
*
|
|
5314
|
+
* @param milliseconds - Duration or repeat interval in milliseconds.
|
|
5315
|
+
* @returns Label such as `5 minutes` or `1 hour 30 minutes`.
|
|
5316
|
+
*
|
|
5317
|
+
* @private internal utility of `<Chat/>` and the Agents Server planned messages
|
|
5146
5318
|
*/
|
|
5147
|
-
|
|
5319
|
+
function formatTimeoutDurationHuman(milliseconds) {
|
|
5320
|
+
const normalizedMilliseconds = Math.max(0, Math.floor(milliseconds));
|
|
5321
|
+
const totalSeconds = Math.max(1, Math.floor(normalizedMilliseconds / SECOND_IN_MILLISECONDS));
|
|
5322
|
+
if (totalSeconds < MINUTE_IN_SECONDS) {
|
|
5323
|
+
return formatTimeoutUnit(totalSeconds, 'second');
|
|
5324
|
+
}
|
|
5325
|
+
if (totalSeconds < HOUR_IN_SECONDS) {
|
|
5326
|
+
const roundedMinutes = Math.max(1, Math.round(totalSeconds / MINUTE_IN_SECONDS));
|
|
5327
|
+
return formatTimeoutUnit(roundedMinutes, 'minute');
|
|
5328
|
+
}
|
|
5329
|
+
if (totalSeconds < DAY_IN_SECONDS) {
|
|
5330
|
+
const hours = Math.floor(totalSeconds / HOUR_IN_SECONDS);
|
|
5331
|
+
const minutes = Math.floor((totalSeconds % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS);
|
|
5332
|
+
if (minutes === 0) {
|
|
5333
|
+
return formatTimeoutUnit(hours, 'hour');
|
|
5334
|
+
}
|
|
5335
|
+
return `${formatTimeoutUnit(hours, 'hour')} ${formatTimeoutUnit(minutes, 'minute')}`;
|
|
5336
|
+
}
|
|
5337
|
+
const days = Math.floor(totalSeconds / DAY_IN_SECONDS);
|
|
5338
|
+
const hours = Math.floor((totalSeconds % DAY_IN_SECONDS) / HOUR_IN_SECONDS);
|
|
5339
|
+
if (hours === 0) {
|
|
5340
|
+
return formatTimeoutUnit(days, 'day');
|
|
5341
|
+
}
|
|
5342
|
+
return `${formatTimeoutUnit(days, 'day')} ${formatTimeoutUnit(hours, 'hour')}`;
|
|
5343
|
+
}
|
|
5344
|
+
/**
|
|
5345
|
+
* Formats one pluralized timeout unit.
|
|
5346
|
+
*
|
|
5347
|
+
* @private internal timeout-chat helper
|
|
5348
|
+
*/
|
|
5349
|
+
function formatTimeoutUnit(value, unit) {
|
|
5350
|
+
return `${value} ${unit}${value === 1 ? '' : 's'}`;
|
|
5351
|
+
}
|
|
5352
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
5148
5353
|
|
|
5149
5354
|
/**
|
|
5150
5355
|
* Builds the planned-message instructions available to an Agents Server-managed coding agent.
|
|
5151
5356
|
*
|
|
5152
|
-
* Planned messages always target the agent's singleton goal chat, regardless of the chat in which
|
|
5153
|
-
*
|
|
5357
|
+
* Planned messages always target the agent's singleton goal chat, regardless of the chat in which the
|
|
5358
|
+
* wake-up is planned, and they repeat like `setInterval` until they are cancelled. The sidecar file is
|
|
5359
|
+
* the only channel that changes them, so an answer that merely claims a follow-up was planned changes
|
|
5360
|
+
* nothing — and an answer that changes nothing keeps the current plan running.
|
|
5361
|
+
*
|
|
5362
|
+
* @param sidecar - Sidecar prepared by the Agents Server for the answered message.
|
|
5363
|
+
* @returns Prompt section, or an empty string outside Agents Server-managed runs.
|
|
5154
5364
|
*/
|
|
5155
|
-
function buildAgentGoalChatPromptSection(
|
|
5156
|
-
if (!
|
|
5365
|
+
function buildAgentGoalChatPromptSection(sidecar) {
|
|
5366
|
+
if (!sidecar) {
|
|
5157
5367
|
return '';
|
|
5158
5368
|
}
|
|
5159
|
-
return spaceTrim$1(`
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
You can plan a future message that wakes you in your singleton goal chat. These commands are available during every Agents Server-managed chat invocation, not only while answering inside the goal chat.
|
|
5369
|
+
return spaceTrim$1((block) => `
|
|
5370
|
+
## Planned goal-chat messages
|
|
5163
5371
|
|
|
5164
|
-
|
|
5165
|
-
- Use \`set_timeout\` when useful work should resume later. The delay is a positive number of milliseconds and the message should say exactly what your future invocation needs to do.
|
|
5166
|
-
- Use \`cancel_timeout\` with the returned \`timeoutId\` when a planned message is no longer useful.
|
|
5167
|
-
- A fired message appears in the goal chat and invokes you there. If more future work remains, plan the next useful message during that invocation.
|
|
5372
|
+
You can plan a message that repeatedly wakes you in your singleton goal chat. A planned message works like \`setInterval\`, not like \`setTimeout\`: once planned, it keeps waking you at its interval until you cancel it. This works during every Agents Server-managed chat invocation, not only while answering inside the goal chat.
|
|
5168
5373
|
|
|
5169
|
-
|
|
5374
|
+
${block(buildCurrentPlannedMessagesLines(sidecar.currentPlannedMessages))}
|
|
5170
5375
|
|
|
5171
|
-
|
|
5172
|
-
# list_timeouts
|
|
5173
|
-
curl -sS -X POST "$${runtimeApi.serverUrlEnvironmentVariableName}${AGENT_GOAL_CHAT_PLANNED_MESSAGES_INTERNAL_API_PATH}" \\
|
|
5174
|
-
-H "Content-Type: application/json" \\
|
|
5175
|
-
-H "${USER_CHAT_WORKER_TOKEN_HEADER}: $${runtimeApi.tokenEnvironmentVariableName}" \\
|
|
5176
|
-
-d '{"action":"list","agentPermanentId":"${runtimeApi.agentPermanentId}"}'
|
|
5376
|
+
Editing \`${sidecar.relativeSidecarPath}\` is the **only** way to change what wakes you. Writing in your answer that you scheduled something does not schedule anything.
|
|
5177
5377
|
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5378
|
+
- **Keeping your planned messages as they are is the default.** When the list above already matches your goal, leave \`commands\` empty — every listed message keeps repeating on its own, and re-planning it would only duplicate it.
|
|
5379
|
+
- When your goal needs a repeating wake-up that is not listed above, append \`{"action":"set","milliseconds":<repeat interval>,"message":"<what each future invocation must do>"}\` to the \`commands\` array of that file.
|
|
5380
|
+
- When a listed message no longer matches your goal (for example your goal now says every 10 minutes while the message repeats every 5 minutes), append \`{"action":"cancel","timeoutId":"<timeout id>"}\` and one \`set\` command with the interval your goal really requires.
|
|
5381
|
+
- When your goal no longer needs a listed message at all, cancel it without planning a replacement.
|
|
5382
|
+
- Never edit \`version\`, \`agentPermanentId\`, or \`currentPlannedMessages\`.
|
|
5383
|
+
- The Agents Server applies every command once your answer is finished, and each repetition appears in the goal chat and invokes you there.
|
|
5384
|
+
- Only mention a planned follow-up in your answer when it is really planned: either you appended the matching \`set\` command, or you kept one of the messages listed above.
|
|
5385
|
+
`);
|
|
5386
|
+
}
|
|
5387
|
+
/**
|
|
5388
|
+
* Renders the already planned messages so the agent can compare them with its goal.
|
|
5389
|
+
*
|
|
5390
|
+
* @param currentPlannedMessages - Planned messages prepared by the Agents Server.
|
|
5391
|
+
* @returns Markdown list, or a sentence stating that nothing is planned yet.
|
|
5392
|
+
*
|
|
5393
|
+
* @private function of `buildAgentGoalChatPromptSection`
|
|
5394
|
+
*/
|
|
5395
|
+
function buildCurrentPlannedMessagesLines(currentPlannedMessages) {
|
|
5396
|
+
if (currentPlannedMessages.length === 0) {
|
|
5397
|
+
return 'You currently have no planned messages waiting.';
|
|
5398
|
+
}
|
|
5399
|
+
const plannedMessageLines = currentPlannedMessages.map(createCurrentPlannedMessageLine);
|
|
5400
|
+
return spaceTrim$1((block) => `
|
|
5401
|
+
These planned messages are already waiting for you, so keep them unless they stopped matching your goal:
|
|
5183
5402
|
|
|
5184
|
-
|
|
5185
|
-
|
|
5186
|
-
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
|
|
5190
|
-
|
|
5403
|
+
${block(plannedMessageLines.join('\n'))}
|
|
5404
|
+
`);
|
|
5405
|
+
}
|
|
5406
|
+
/**
|
|
5407
|
+
* Renders one already planned message with the schedule the agent has to compare with its goal.
|
|
5408
|
+
*
|
|
5409
|
+
* @param plannedMessage - One planned message prepared by the Agents Server.
|
|
5410
|
+
* @returns Markdown list item.
|
|
5411
|
+
*
|
|
5412
|
+
* @private function of `buildAgentGoalChatPromptSection`
|
|
5413
|
+
*/
|
|
5414
|
+
function createCurrentPlannedMessageLine(plannedMessage) {
|
|
5415
|
+
var _a;
|
|
5416
|
+
const message = ((_a = plannedMessage.message) === null || _a === void 0 ? void 0 : _a.trim()) || 'Continue working towards the current goal.';
|
|
5417
|
+
const schedule = plannedMessage.intervalMs
|
|
5418
|
+
? `repeats every ${formatTimeoutDurationHuman(plannedMessage.intervalMs)}`
|
|
5419
|
+
: `wakes you once at ${plannedMessage.dueAt}`;
|
|
5420
|
+
return `- \`${plannedMessage.timeoutId}\` ${schedule}: ${message}`;
|
|
5191
5421
|
}
|
|
5192
5422
|
|
|
5193
5423
|
// Note: [💞] This file defines the shared TEAM workspace convention rather than one standalone entity.
|
|
@@ -5218,8 +5448,8 @@ function buildAgentTeamPromptSection(workspace) {
|
|
|
5218
5448
|
return '';
|
|
5219
5449
|
}
|
|
5220
5450
|
const teammateSections = workspace.manifest.teammates.map((teammate) => {
|
|
5221
|
-
const sourcePath = toPromptPath(join(workspace.relativeWorkspacePath, AGENT_TEAMMATE_SOURCES_DIRECTORY_NAME, teammate.sourceFileName));
|
|
5222
|
-
const transcriptPath = toPromptPath(join(workspace.relativeWorkspacePath, `${teammate.permanentId}--01.book`));
|
|
5451
|
+
const sourcePath = toPromptPath$1(join(workspace.relativeWorkspacePath, AGENT_TEAMMATE_SOURCES_DIRECTORY_NAME, teammate.sourceFileName));
|
|
5452
|
+
const transcriptPath = toPromptPath$1(join(workspace.relativeWorkspacePath, `${teammate.permanentId}--01.book`));
|
|
5223
5453
|
const instructions = teammate.instructions.trim() || 'No additional TEAM instructions were provided.';
|
|
5224
5454
|
return spaceTrim$1(`
|
|
5225
5455
|
- ${teammate.agentName}
|
|
@@ -5237,7 +5467,7 @@ function buildAgentTeamPromptSection(workspace) {
|
|
|
5237
5467
|
|
|
5238
5468
|
- The underlying coding harness is already executing this turn **exactly once**. Never start, queue, or invoke another coding harness, agent runner, or \`ptbk\` command to consult a teammate.
|
|
5239
5469
|
- The primary agent remains responsible for the final user-facing \`MESSAGE @Agent\` answer.
|
|
5240
|
-
- Teammate source files are read-only context. When a teammate consultation occurs, record the actual exchange in a new top-level \`.book\` file in \`${toPromptPath(workspace.relativeWorkspacePath)}\`.
|
|
5470
|
+
- Teammate source files are read-only context. When a teammate consultation occurs, record the actual exchange in a new top-level \`.book\` file in \`${toPromptPath$1(workspace.relativeWorkspacePath)}\`.
|
|
5241
5471
|
- Name each transcript \`<teammate permanent id>--<sequence>.book\`, for example \`${workspace.manifest.teammates[0].permanentId}--01.book\`.
|
|
5242
5472
|
- Every transcript must contain alternating \`MESSAGE @${workspace.manifest.primaryAgent.agentName}\` and \`MESSAGE @<teammate name>\` blocks. Do not create a transcript for a teammate that was not consulted.
|
|
5243
5473
|
`);
|
|
@@ -5245,7 +5475,7 @@ function buildAgentTeamPromptSection(workspace) {
|
|
|
5245
5475
|
/**
|
|
5246
5476
|
* Converts a filesystem-relative path into the portable path notation used in prompts.
|
|
5247
5477
|
*/
|
|
5248
|
-
function toPromptPath(path) {
|
|
5478
|
+
function toPromptPath$1(path) {
|
|
5249
5479
|
return path.replace(/\\/gu, '/');
|
|
5250
5480
|
}
|
|
5251
5481
|
|
|
@@ -5258,7 +5488,7 @@ function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage, option
|
|
|
5258
5488
|
|
|
5259
5489
|
- Read \`${messageRelativePath}\` and answer the most recent \`MESSAGE\` block. In a normal chat it is from \`@User\`; in your internal goal chat it can be from \`@Agent\`.
|
|
5260
5490
|
- Only change the queued message file by appending one new \`MESSAGE @Agent\` block
|
|
5261
|
-
${block(buildAllowedFileChangesPromptLine(options
|
|
5491
|
+
${block(buildAllowedFileChangesPromptLine(options))}
|
|
5262
5492
|
|
|
5263
5493
|
## Rules for the answering
|
|
5264
5494
|
|
|
@@ -5294,7 +5524,7 @@ function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage, option
|
|
|
5294
5524
|
|
|
5295
5525
|
- You can use \`message\` for message that will be sent immediately after clicking the button, or \`messageDraft\` for message that will be prefilled in the input field for editing before sending.
|
|
5296
5526
|
|
|
5297
|
-
${block(buildAgentGoalChatPromptSection(options.
|
|
5527
|
+
${block(buildAgentGoalChatPromptSection(options.plannedMessagesSidecar))}
|
|
5298
5528
|
|
|
5299
5529
|
${block(buildAgentProjectsPromptSection(options))}
|
|
5300
5530
|
|
|
@@ -5308,11 +5538,30 @@ function buildAgentMessagePrompt(messageRelativePath, agentSystemMessage, option
|
|
|
5308
5538
|
/**
|
|
5309
5539
|
* Explains the exact files that one coding harness may change for a user turn.
|
|
5310
5540
|
*/
|
|
5311
|
-
function buildAllowedFileChangesPromptLine(
|
|
5312
|
-
|
|
5313
|
-
|
|
5541
|
+
function buildAllowedFileChangesPromptLine(options) {
|
|
5542
|
+
const allowedFileChanges = [`files inside your own \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory`];
|
|
5543
|
+
if (options.teamWorkspace) {
|
|
5544
|
+
allowedFileChanges.push(`new consultation transcripts inside \`${toPromptPath(options.teamWorkspace.relativeWorkspacePath)}\``);
|
|
5545
|
+
}
|
|
5546
|
+
if (options.plannedMessagesSidecar) {
|
|
5547
|
+
allowedFileChanges.push(`the \`commands\` array of \`${toPromptPath(options.plannedMessagesSidecar.relativeSidecarPath)}\``);
|
|
5314
5548
|
}
|
|
5315
|
-
return `- Do not modify any other file in the repository, except
|
|
5549
|
+
return `- Do not modify any other file in the repository, except ${formatAllowedFileChanges(allowedFileChanges)}`;
|
|
5550
|
+
}
|
|
5551
|
+
/**
|
|
5552
|
+
* Joins the allowed file-change phrases into one readable enumeration.
|
|
5553
|
+
*/
|
|
5554
|
+
function formatAllowedFileChanges(allowedFileChanges) {
|
|
5555
|
+
if (allowedFileChanges.length === 1) {
|
|
5556
|
+
return allowedFileChanges[0];
|
|
5557
|
+
}
|
|
5558
|
+
return `${allowedFileChanges.slice(0, -1).join(', ')} and ${allowedFileChanges[allowedFileChanges.length - 1]}`;
|
|
5559
|
+
}
|
|
5560
|
+
/**
|
|
5561
|
+
* Converts a filesystem-relative path into the portable path notation used in prompts.
|
|
5562
|
+
*/
|
|
5563
|
+
function toPromptPath(path) {
|
|
5564
|
+
return path.replace(/\\/gu, '/');
|
|
5316
5565
|
}
|
|
5317
5566
|
|
|
5318
5567
|
/**
|
|
@@ -27327,6 +27576,30 @@ function applyCommitmentDefinitionSafely(requirements, commitment, commitmentCon
|
|
|
27327
27576
|
}
|
|
27328
27577
|
}
|
|
27329
27578
|
|
|
27579
|
+
/**
|
|
27580
|
+
* Pattern shared by Book parsing and editor highlighting for a commitment-like line.
|
|
27581
|
+
*
|
|
27582
|
+
* A Book commitment keyword consists of one or more all-uppercase words with at least
|
|
27583
|
+
* two characters each. This deliberately mirrors the Book editor syntax rule so an
|
|
27584
|
+
* unknown keyword starts a new source block everywhere it is interpreted.
|
|
27585
|
+
*
|
|
27586
|
+
* @private internal constant of `getBookCommitmentLineType`
|
|
27587
|
+
*/
|
|
27588
|
+
const BOOK_COMMITMENT_LINE_TYPE_REGEX = /^\s*(?<type>[A-Z][A-Z0-9]+(?:\s+[A-Z][A-Z0-9]+)*)(?=\s|$)/;
|
|
27589
|
+
/**
|
|
27590
|
+
* Extracts the uppercase commitment type from a Book line, including types not registered by Promptbook.
|
|
27591
|
+
*
|
|
27592
|
+
* @param line - One raw Book source line.
|
|
27593
|
+
* @returns Matched commitment type or `null` when the line does not begin with commitment syntax.
|
|
27594
|
+
*
|
|
27595
|
+
* @private internal utility of Book parsing and `<BookEditor/>`
|
|
27596
|
+
*/
|
|
27597
|
+
function getBookCommitmentLineType(line) {
|
|
27598
|
+
var _a;
|
|
27599
|
+
const match = BOOK_COMMITMENT_LINE_TYPE_REGEX.exec(line);
|
|
27600
|
+
return ((_a = match === null || match === void 0 ? void 0 : match.groups) === null || _a === void 0 ? void 0 : _a.type) || null;
|
|
27601
|
+
}
|
|
27602
|
+
|
|
27330
27603
|
/**
|
|
27331
27604
|
* Consumes the agent-name prelude from raw source.
|
|
27332
27605
|
*
|
|
@@ -27384,13 +27657,15 @@ function parseAgentSourceWithCommitments(agentSource) {
|
|
|
27384
27657
|
return {
|
|
27385
27658
|
agentName: null,
|
|
27386
27659
|
commitments: [],
|
|
27660
|
+
unknownCommitments: [],
|
|
27387
27661
|
nonCommitmentLines: [],
|
|
27388
27662
|
};
|
|
27389
27663
|
}
|
|
27390
27664
|
const { lines, agentName, agentNameLineIndex, agentNameLineNumber } = parseAgentSourcePrelude(agentSource);
|
|
27391
27665
|
const commitments = [];
|
|
27666
|
+
const unknownCommitments = [];
|
|
27392
27667
|
const nonCommitmentLines = agentNameLineIndex >= 0 ? [lines[agentNameLineIndex]] : [];
|
|
27393
|
-
// Parse commitments with multiline support
|
|
27668
|
+
// Parse commitments with multiline support.
|
|
27394
27669
|
let currentCommitment = null;
|
|
27395
27670
|
// Process lines starting from after the agent name line
|
|
27396
27671
|
const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
|
|
@@ -27404,25 +27679,11 @@ function parseAgentSourceWithCommitments(agentSource) {
|
|
|
27404
27679
|
// Check if this line starts or ends a code block
|
|
27405
27680
|
if (trimmedLine.startsWith('```')) {
|
|
27406
27681
|
isInsideCodeBlock = !isInsideCodeBlock;
|
|
27407
|
-
|
|
27408
|
-
// If we are inside a commitment, the code block is part of it
|
|
27409
|
-
currentCommitment.contentLines.push(line);
|
|
27410
|
-
}
|
|
27411
|
-
else {
|
|
27412
|
-
// If we are not inside a commitment, the code block is non-commitment
|
|
27413
|
-
nonCommitmentLines.push(line);
|
|
27414
|
-
}
|
|
27682
|
+
appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
|
|
27415
27683
|
continue;
|
|
27416
27684
|
}
|
|
27417
27685
|
if (isInsideCodeBlock) {
|
|
27418
|
-
|
|
27419
|
-
// If we are inside a commitment and a code block, the line is part of the commitment
|
|
27420
|
-
currentCommitment.contentLines.push(line);
|
|
27421
|
-
}
|
|
27422
|
-
else {
|
|
27423
|
-
// If we are inside a code block but not a commitment, the line is non-commitment
|
|
27424
|
-
nonCommitmentLines.push(line);
|
|
27425
|
-
}
|
|
27686
|
+
appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
|
|
27426
27687
|
continue;
|
|
27427
27688
|
}
|
|
27428
27689
|
// Check if this line starts a new commitment
|
|
@@ -27431,22 +27692,14 @@ function parseAgentSourceWithCommitments(agentSource) {
|
|
|
27431
27692
|
const typeRegex = definition.createTypeRegex();
|
|
27432
27693
|
const match = typeRegex.exec(line.trim());
|
|
27433
27694
|
if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
27434
|
-
|
|
27435
|
-
if (currentCommitment) {
|
|
27436
|
-
const fullContent = currentCommitment.contentLines.join('\n');
|
|
27437
|
-
commitments.push({
|
|
27438
|
-
type: currentCommitment.type,
|
|
27439
|
-
content: spaceTrim$1(fullContent),
|
|
27440
|
-
originalLine: currentCommitment.originalStartLine,
|
|
27441
|
-
lineNumber: currentCommitment.startLineNumber,
|
|
27442
|
-
});
|
|
27443
|
-
}
|
|
27695
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
27444
27696
|
// Extract the initial content from the commitment line
|
|
27445
27697
|
const fullRegex = definition.createRegex();
|
|
27446
27698
|
const fullMatch = fullRegex.exec(line.trim());
|
|
27447
27699
|
const initialContent = ((_b = fullMatch === null || fullMatch === void 0 ? void 0 : fullMatch.groups) === null || _b === void 0 ? void 0 : _b.contents) || '';
|
|
27448
27700
|
// Start a new commitment
|
|
27449
27701
|
currentCommitment = {
|
|
27702
|
+
kind: 'known',
|
|
27450
27703
|
type: definition.type,
|
|
27451
27704
|
startLineNumber: i + 1,
|
|
27452
27705
|
originalStartLine: line,
|
|
@@ -27456,52 +27709,90 @@ function parseAgentSourceWithCommitments(agentSource) {
|
|
|
27456
27709
|
break;
|
|
27457
27710
|
}
|
|
27458
27711
|
}
|
|
27712
|
+
if (foundNewCommitment) {
|
|
27713
|
+
continue;
|
|
27714
|
+
}
|
|
27715
|
+
const unknownCommitmentType = getBookCommitmentLineType(line);
|
|
27716
|
+
if (unknownCommitmentType) {
|
|
27717
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
27718
|
+
currentCommitment = {
|
|
27719
|
+
kind: 'unknown',
|
|
27720
|
+
type: unknownCommitmentType,
|
|
27721
|
+
startLineNumber: i + 1,
|
|
27722
|
+
originalStartLine: line,
|
|
27723
|
+
sourceLines: [line],
|
|
27724
|
+
};
|
|
27725
|
+
continue;
|
|
27726
|
+
}
|
|
27459
27727
|
// Check if this is a horizontal line (ends any current commitment)
|
|
27460
27728
|
const isHorizontalLine = HORIZONTAL_LINE_PATTERN$1.test(line);
|
|
27461
27729
|
if (isHorizontalLine) {
|
|
27462
|
-
|
|
27463
|
-
|
|
27464
|
-
const fullContent = currentCommitment.contentLines.join('\n');
|
|
27465
|
-
commitments.push({
|
|
27466
|
-
type: currentCommitment.type,
|
|
27467
|
-
content: spaceTrim$1(fullContent),
|
|
27468
|
-
originalLine: currentCommitment.originalStartLine,
|
|
27469
|
-
lineNumber: currentCommitment.startLineNumber,
|
|
27470
|
-
});
|
|
27471
|
-
currentCommitment = null;
|
|
27472
|
-
}
|
|
27730
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
27731
|
+
currentCommitment = null;
|
|
27473
27732
|
// Add horizontal line to non-commitment lines
|
|
27474
27733
|
nonCommitmentLines.push(line);
|
|
27475
27734
|
continue;
|
|
27476
27735
|
}
|
|
27477
|
-
|
|
27478
|
-
if (currentCommitment) {
|
|
27479
|
-
// This line belongs to the current commitment
|
|
27480
|
-
currentCommitment.contentLines.push(line);
|
|
27481
|
-
}
|
|
27482
|
-
else {
|
|
27483
|
-
// This line is not part of any commitment
|
|
27484
|
-
nonCommitmentLines.push(line);
|
|
27485
|
-
}
|
|
27486
|
-
}
|
|
27487
|
-
}
|
|
27488
|
-
// Don't forget to save the last commitment if it exists
|
|
27489
|
-
if (currentCommitment) {
|
|
27490
|
-
const fullContent = currentCommitment.contentLines.join('\n');
|
|
27491
|
-
commitments.push({
|
|
27492
|
-
type: currentCommitment.type,
|
|
27493
|
-
content: spaceTrim$1(fullContent),
|
|
27494
|
-
originalLine: currentCommitment.originalStartLine,
|
|
27495
|
-
lineNumber: currentCommitment.startLineNumber,
|
|
27496
|
-
});
|
|
27736
|
+
appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
|
|
27497
27737
|
}
|
|
27738
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
27498
27739
|
return {
|
|
27499
27740
|
agentName,
|
|
27500
27741
|
agentNameLineNumber,
|
|
27501
27742
|
commitments,
|
|
27743
|
+
unknownCommitments,
|
|
27502
27744
|
nonCommitmentLines,
|
|
27503
27745
|
};
|
|
27504
27746
|
}
|
|
27747
|
+
/**
|
|
27748
|
+
* Stores the current known or unknown commitment in its appropriate parsed collection.
|
|
27749
|
+
*
|
|
27750
|
+
* @param currentCommitment - Commitment-like block collected so far.
|
|
27751
|
+
* @param commitments - Parsed registered commitments to append to.
|
|
27752
|
+
* @param unknownCommitments - Parsed unregistered commitments to append to.
|
|
27753
|
+
*
|
|
27754
|
+
* @private internal utility of `parseAgentSourceWithCommitments`
|
|
27755
|
+
*/
|
|
27756
|
+
function appendCurrentCommitment(currentCommitment, commitments, unknownCommitments) {
|
|
27757
|
+
if (!currentCommitment) {
|
|
27758
|
+
return;
|
|
27759
|
+
}
|
|
27760
|
+
if (currentCommitment.kind === 'unknown') {
|
|
27761
|
+
unknownCommitments.push({
|
|
27762
|
+
type: currentCommitment.type,
|
|
27763
|
+
originalLine: currentCommitment.originalStartLine,
|
|
27764
|
+
lineNumber: currentCommitment.startLineNumber,
|
|
27765
|
+
source: spaceTrim$1(currentCommitment.sourceLines.join('\n')),
|
|
27766
|
+
});
|
|
27767
|
+
return;
|
|
27768
|
+
}
|
|
27769
|
+
commitments.push({
|
|
27770
|
+
type: currentCommitment.type,
|
|
27771
|
+
content: spaceTrim$1(currentCommitment.contentLines.join('\n')),
|
|
27772
|
+
originalLine: currentCommitment.originalStartLine,
|
|
27773
|
+
lineNumber: currentCommitment.startLineNumber,
|
|
27774
|
+
});
|
|
27775
|
+
}
|
|
27776
|
+
/**
|
|
27777
|
+
* Adds one source line to the active commitment-like block, or to plain source content when none is active.
|
|
27778
|
+
*
|
|
27779
|
+
* @param currentCommitment - Commitment-like block currently being collected.
|
|
27780
|
+
* @param line - Source line to append.
|
|
27781
|
+
* @param nonCommitmentLines - Plain source lines to append to when no block is active.
|
|
27782
|
+
*
|
|
27783
|
+
* @private internal utility of `parseAgentSourceWithCommitments`
|
|
27784
|
+
*/
|
|
27785
|
+
function appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines) {
|
|
27786
|
+
if (!currentCommitment) {
|
|
27787
|
+
nonCommitmentLines.push(line);
|
|
27788
|
+
return;
|
|
27789
|
+
}
|
|
27790
|
+
if (currentCommitment.kind === 'unknown') {
|
|
27791
|
+
currentCommitment.sourceLines.push(line);
|
|
27792
|
+
return;
|
|
27793
|
+
}
|
|
27794
|
+
currentCommitment.contentLines.push(line);
|
|
27795
|
+
}
|
|
27505
27796
|
|
|
27506
27797
|
/**
|
|
27507
27798
|
* Plugin for importing agent books *(`.book` files)*
|
|
@@ -27639,7 +27930,8 @@ async function augmentAgentModelRequirementsFromSource(requirements, parseResult
|
|
|
27639
27930
|
requirements = await importReferencedFiles(requirements);
|
|
27640
27931
|
requirements = appendMcpServers(requirements, agentSource);
|
|
27641
27932
|
requirements = appendNonCommitmentContent(requirements, parseResult);
|
|
27642
|
-
|
|
27933
|
+
requirements = appendExampleInteractions(requirements, parseResult);
|
|
27934
|
+
return appendUnknownCommitmentContent(requirements, parseResult);
|
|
27643
27935
|
}
|
|
27644
27936
|
/**
|
|
27645
27937
|
* Imports text files referenced by IMPORT commitments and appends their transformed content to the system message.
|
|
@@ -27761,6 +28053,36 @@ function appendNonCommitmentContent(requirements, parseResult) {
|
|
|
27761
28053
|
}
|
|
27762
28054
|
return appendSystemMessageSection(requirements, nonCommitmentContent);
|
|
27763
28055
|
}
|
|
28056
|
+
/**
|
|
28057
|
+
* Appends unknown commitment blocks as final extra context without applying commitment side effects.
|
|
28058
|
+
*
|
|
28059
|
+
* @param requirements - Current requirements snapshot.
|
|
28060
|
+
* @param parseResult - Parsed source including unknown commitment blocks.
|
|
28061
|
+
* @returns Requirements with unknown commitment context appended at the end of the system message.
|
|
28062
|
+
*
|
|
28063
|
+
* @private internal utility of `augmentAgentModelRequirementsFromSource`
|
|
28064
|
+
*/
|
|
28065
|
+
function appendUnknownCommitmentContent(requirements, parseResult) {
|
|
28066
|
+
const unknownCommitmentContent = getUnknownCommitmentContent(parseResult);
|
|
28067
|
+
if (!unknownCommitmentContent) {
|
|
28068
|
+
return requirements;
|
|
28069
|
+
}
|
|
28070
|
+
return appendSystemMessageSection(requirements, unknownCommitmentContent);
|
|
28071
|
+
}
|
|
28072
|
+
/**
|
|
28073
|
+
* Joins unknown commitment blocks into their final extra-context representation.
|
|
28074
|
+
*
|
|
28075
|
+
* @param parseResult - Parsed source including unknown commitment blocks.
|
|
28076
|
+
* @returns Unknown commitment source blocks in their original order.
|
|
28077
|
+
*
|
|
28078
|
+
* @private internal utility of `appendUnknownCommitmentContent`
|
|
28079
|
+
*/
|
|
28080
|
+
function getUnknownCommitmentContent(parseResult) {
|
|
28081
|
+
return parseResult.unknownCommitments
|
|
28082
|
+
.map((commitment) => commitment.source)
|
|
28083
|
+
.filter(Boolean)
|
|
28084
|
+
.join('\n\n');
|
|
28085
|
+
}
|
|
27764
28086
|
/**
|
|
27765
28087
|
* Collects plain-text lines that were not parsed as commitments and should still become part of the final system message.
|
|
27766
28088
|
*
|
|
@@ -39735,23 +40057,27 @@ async function locateAppOnMacOs({ macOsName, }) {
|
|
|
39735
40057
|
// TODO: [🧠][♿] Maybe export through `@promptbook/node`
|
|
39736
40058
|
|
|
39737
40059
|
/**
|
|
39738
|
-
* Attempts to locate the specified application on a Windows system by searching common installation directories.
|
|
40060
|
+
* Attempts to locate the specified application on a Windows system by searching PATH and common installation directories.
|
|
39739
40061
|
* Returns the path to the executable if found, or null otherwise.
|
|
39740
40062
|
*
|
|
39741
40063
|
* @private within the repository
|
|
39742
40064
|
*/
|
|
39743
40065
|
async function locateAppOnWindows({ appName, windowsSuffix, }) {
|
|
39744
40066
|
try {
|
|
39745
|
-
const
|
|
40067
|
+
const EXECUTABLE_FILENAME = windowsSuffix.replace(/^.*[\\/]/, '');
|
|
40068
|
+
const PATH_EXECUTABLE_PATHS = (process.env.PATH || '')
|
|
40069
|
+
.split(delimiter)
|
|
40070
|
+
.filter(Boolean)
|
|
40071
|
+
.map((pathPrefix) => join(pathPrefix, EXECUTABLE_FILENAME));
|
|
40072
|
+
const INSTALLATION_EXECUTABLE_PATHS = [
|
|
39746
40073
|
process.env.LOCALAPPDATA,
|
|
39747
40074
|
join(process.env.LOCALAPPDATA || '', 'Programs'),
|
|
39748
40075
|
process.env.PROGRAMFILES,
|
|
39749
40076
|
process.env['PROGRAMFILES(X86)'],
|
|
39750
|
-
];
|
|
39751
|
-
for (const
|
|
39752
|
-
|
|
39753
|
-
|
|
39754
|
-
return path;
|
|
40077
|
+
].map((pathPrefix) => pathPrefix + windowsSuffix);
|
|
40078
|
+
for (const executablePath of [...PATH_EXECUTABLE_PATHS, ...INSTALLATION_EXECUTABLE_PATHS]) {
|
|
40079
|
+
if (await isExecutable(executablePath, $provideFilesystemForNode())) {
|
|
40080
|
+
return executablePath;
|
|
39755
40081
|
}
|
|
39756
40082
|
}
|
|
39757
40083
|
throw new Error(`Can not locate app ${appName} on Windows.`);
|