@promptbook/cli 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/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +8 -1
- package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +193 -63
- package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +25 -28
- package/apps/agents-server/src/app/admin/messages/send-email/emailTesting.ts +153 -0
- package/apps/agents-server/src/app/admin/messages/send-email/emailTestingAccess.ts +30 -0
- package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +18 -5
- package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +7 -4
- package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatPlannedMessages.tsx +23 -8
- package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +14 -3
- package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +2 -20
- package/apps/agents-server/src/app/agents/[agentName]/page.tsx +2 -1
- package/apps/agents-server/src/app/agents/[agentName]/projectReferenceActions.ts +61 -0
- package/apps/agents-server/src/app/api/internal/agent-goal-chat-planned-messages/route.ts +34 -7
- package/apps/agents-server/src/components/AgentProjects/resolveLatestCompletedAgentMessageKey.ts +32 -0
- package/apps/agents-server/src/components/AgentProjects/useAgentProjectMarkdownReferences.ts +124 -2
- package/apps/agents-server/src/languages/ServerTranslationKeys.ts +3 -0
- package/apps/agents-server/src/languages/translations/czech.yaml +3 -0
- package/apps/agents-server/src/languages/translations/english.yaml +3 -0
- package/apps/agents-server/src/message-providers/email/stalwart/StalwartMessageProvider.ts +2 -1
- package/apps/agents-server/src/tools/agentGoalChatTimeoutToolFunctions.ts +24 -2
- package/apps/agents-server/src/tools/agentGoalChatTimeoutTools.ts +5 -4
- package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatPlannedMessageActions.ts +38 -9
- package/apps/agents-server/src/utils/agentGoalChat/createAgentGoalChatNoteContent.ts +15 -6
- package/apps/agents-server/src/utils/agentProjects/listAgentProjectNames.ts +35 -0
- package/apps/agents-server/src/utils/agentProjects/listAgentProjects.ts +6 -23
- package/apps/agents-server/src/utils/agentProjects/resolveAgentChatProjectReferences.ts +25 -0
- package/apps/agents-server/src/utils/chatMessageChips/createAnsweredMessageChipToolCalls.ts +37 -0
- package/apps/agents-server/src/utils/chatMessageChips/createPlannedMessageChipToolCalls.ts +39 -0
- package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipToolCalls.ts +75 -0
- package/apps/agents-server/src/utils/email/agentEmailAddress.ts +14 -0
- package/apps/agents-server/src/utils/email/sendEmailThroughStalwart.ts +2 -1
- package/apps/agents-server/src/utils/localChatRunner/applyLocalAgentPlannedMessageCommands.ts +212 -0
- package/apps/agents-server/src/utils/localChatRunner/prepareLocalAgentPlannedMessagesSidecar.ts +66 -0
- package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +110 -22
- package/apps/agents-server/src/utils/userChat/persistUserChatJobTerminalState.ts +5 -0
- package/apps/agents-server/src/utils/userChat/userChatJobRunReport.ts +30 -0
- package/apps/agents-server/src/utils/userChatTimeout/createTimeoutWakeUpMessage.ts +9 -1
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/repeatFiredUserChatTimeout.ts +74 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore.ts +1 -0
- package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutWorker.ts +63 -54
- package/esm/index.es.js +1042 -194
- 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-agent-messages/messages/loadAgentPlannedMessagesSidecar.d.ts +10 -0
- package/esm/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +15 -0
- 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 +1 -1
- package/src/book-2.0/agent-source/AgentSourceParseResult.ts +6 -0
- package/src/book-2.0/agent-source/ParsedUnknownCommitment.ts +29 -0
- package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +38 -1
- package/src/book-2.0/agent-source/getBookCommitmentLineType.ts +36 -0
- package/src/book-2.0/agent-source/parseAgentSourceWithCommitments.ts +128 -61
- package/src/book-3.0/AgentMessageRunReport.ts +76 -0
- package/src/book-3.0/AgentPlannedMessagesSidecar.ts +229 -0
- package/src/book-3.0/AgentTeamConversationWorkspace.ts +3 -5
- package/src/book-3.0/createAgentMessageSidecarBaseName.ts +20 -0
- package/src/book-components/BookEditor/BookEditorMonaco.tsx +6 -1
- package/src/book-components/BookEditor/BookEditorMonacoTokenization.ts +3 -1
- package/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.ts +50 -0
- package/src/book-components/Chat/Chat/Chat.module.css +6 -1
- package/src/book-components/Chat/Chat/renderToolCallDetails.tsx +1 -12
- package/src/book-components/Chat/utils/agentProjectToolCall.ts +74 -0
- package/src/book-components/Chat/utils/getToolCallChipletInfo.ts +28 -0
- package/src/book-components/Chat/utils/timeoutToolCallPresentation.ts +23 -3
- package/src/cli/cli-commands/coder/boilerplateTemplates.ts +3 -15
- package/src/cli/cli-commands/coder/init.ts +11 -2
- package/src/cli/cli-commands/coder/ping.ts +11 -1
- package/src/cli/cli-commands/coder/run.ts +11 -2
- package/src/cli/cli-commands/coder/server.ts +11 -2
- package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +5 -0
- package/src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts +17 -5
- package/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.ts +6 -3
- package/src/cli/cli-commands/common/harness/HarnessInstallationStatus.ts +3 -2
- package/src/cli/cli-commands/common/harnessUpdateCliOptions.ts +49 -0
- package/src/executables/platforms/locateAppOnWindows.ts +12 -9
- package/src/other/templates/getTemplatesPipelineCollection.ts +740 -860
- package/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.ts +105 -0
- package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +6 -54
- package/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.ts +147 -0
- package/src/version.ts +2 -2
- package/src/versions.txt +2 -1
- package/umd/index.umd.js +1041 -193
- 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-agent-messages/messages/loadAgentPlannedMessagesSidecar.d.ts +10 -0
- package/umd/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +15 -0
- 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/umd/apps/agents-server/src/utils/agentGoalChat/agentGoalChatConstants.d.ts +0 -12
package/umd/index.umd.js
CHANGED
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
* @generated
|
|
59
59
|
* @see https://github.com/webgptorg/promptbook
|
|
60
60
|
*/
|
|
61
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-
|
|
61
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.114.0-13';
|
|
62
62
|
/**
|
|
63
63
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
64
64
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -4098,10 +4098,6 @@
|
|
|
4098
4098
|
* Environment variable containing the internal worker token for local agent runners.
|
|
4099
4099
|
*/
|
|
4100
4100
|
const PTBK_AGENTS_SERVER_USER_CHAT_WORKER_TOKEN_ENV = 'PTBK_AGENTS_SERVER_USER_CHAT_WORKER_TOKEN';
|
|
4101
|
-
/**
|
|
4102
|
-
* Header used by internal local-runner routes.
|
|
4103
|
-
*/
|
|
4104
|
-
const USER_CHAT_WORKER_TOKEN_HEADER = 'x-user-chat-worker-token';
|
|
4105
4101
|
|
|
4106
4102
|
/**
|
|
4107
4103
|
* Format either small or big number
|
|
@@ -20317,6 +20313,30 @@
|
|
|
20317
20313
|
// TODO: [🧠] Maybe create through standardized $register
|
|
20318
20314
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
20319
20315
|
|
|
20316
|
+
/**
|
|
20317
|
+
* Pattern shared by Book parsing and editor highlighting for a commitment-like line.
|
|
20318
|
+
*
|
|
20319
|
+
* A Book commitment keyword consists of one or more all-uppercase words with at least
|
|
20320
|
+
* two characters each. This deliberately mirrors the Book editor syntax rule so an
|
|
20321
|
+
* unknown keyword starts a new source block everywhere it is interpreted.
|
|
20322
|
+
*
|
|
20323
|
+
* @private internal constant of `getBookCommitmentLineType`
|
|
20324
|
+
*/
|
|
20325
|
+
const BOOK_COMMITMENT_LINE_TYPE_REGEX = /^\s*(?<type>[A-Z][A-Z0-9]+(?:\s+[A-Z][A-Z0-9]+)*)(?=\s|$)/;
|
|
20326
|
+
/**
|
|
20327
|
+
* Extracts the uppercase commitment type from a Book line, including types not registered by Promptbook.
|
|
20328
|
+
*
|
|
20329
|
+
* @param line - One raw Book source line.
|
|
20330
|
+
* @returns Matched commitment type or `null` when the line does not begin with commitment syntax.
|
|
20331
|
+
*
|
|
20332
|
+
* @private internal utility of Book parsing and `<BookEditor/>`
|
|
20333
|
+
*/
|
|
20334
|
+
function getBookCommitmentLineType(line) {
|
|
20335
|
+
var _a;
|
|
20336
|
+
const match = BOOK_COMMITMENT_LINE_TYPE_REGEX.exec(line);
|
|
20337
|
+
return ((_a = match === null || match === void 0 ? void 0 : match.groups) === null || _a === void 0 ? void 0 : _a.type) || null;
|
|
20338
|
+
}
|
|
20339
|
+
|
|
20320
20340
|
/**
|
|
20321
20341
|
* Consumes the agent-name prelude from raw source.
|
|
20322
20342
|
*
|
|
@@ -20374,13 +20394,15 @@
|
|
|
20374
20394
|
return {
|
|
20375
20395
|
agentName: null,
|
|
20376
20396
|
commitments: [],
|
|
20397
|
+
unknownCommitments: [],
|
|
20377
20398
|
nonCommitmentLines: [],
|
|
20378
20399
|
};
|
|
20379
20400
|
}
|
|
20380
20401
|
const { lines, agentName, agentNameLineIndex, agentNameLineNumber } = parseAgentSourcePrelude(agentSource);
|
|
20381
20402
|
const commitments = [];
|
|
20403
|
+
const unknownCommitments = [];
|
|
20382
20404
|
const nonCommitmentLines = agentNameLineIndex >= 0 ? [lines[agentNameLineIndex]] : [];
|
|
20383
|
-
// Parse commitments with multiline support
|
|
20405
|
+
// Parse commitments with multiline support.
|
|
20384
20406
|
let currentCommitment = null;
|
|
20385
20407
|
// Process lines starting from after the agent name line
|
|
20386
20408
|
const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
|
|
@@ -20394,25 +20416,11 @@
|
|
|
20394
20416
|
// Check if this line starts or ends a code block
|
|
20395
20417
|
if (trimmedLine.startsWith('```')) {
|
|
20396
20418
|
isInsideCodeBlock = !isInsideCodeBlock;
|
|
20397
|
-
|
|
20398
|
-
// If we are inside a commitment, the code block is part of it
|
|
20399
|
-
currentCommitment.contentLines.push(line);
|
|
20400
|
-
}
|
|
20401
|
-
else {
|
|
20402
|
-
// If we are not inside a commitment, the code block is non-commitment
|
|
20403
|
-
nonCommitmentLines.push(line);
|
|
20404
|
-
}
|
|
20419
|
+
appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
|
|
20405
20420
|
continue;
|
|
20406
20421
|
}
|
|
20407
20422
|
if (isInsideCodeBlock) {
|
|
20408
|
-
|
|
20409
|
-
// If we are inside a commitment and a code block, the line is part of the commitment
|
|
20410
|
-
currentCommitment.contentLines.push(line);
|
|
20411
|
-
}
|
|
20412
|
-
else {
|
|
20413
|
-
// If we are inside a code block but not a commitment, the line is non-commitment
|
|
20414
|
-
nonCommitmentLines.push(line);
|
|
20415
|
-
}
|
|
20423
|
+
appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
|
|
20416
20424
|
continue;
|
|
20417
20425
|
}
|
|
20418
20426
|
// Check if this line starts a new commitment
|
|
@@ -20421,22 +20429,14 @@
|
|
|
20421
20429
|
const typeRegex = definition.createTypeRegex();
|
|
20422
20430
|
const match = typeRegex.exec(line.trim());
|
|
20423
20431
|
if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
20424
|
-
|
|
20425
|
-
if (currentCommitment) {
|
|
20426
|
-
const fullContent = currentCommitment.contentLines.join('\n');
|
|
20427
|
-
commitments.push({
|
|
20428
|
-
type: currentCommitment.type,
|
|
20429
|
-
content: _spaceTrim.spaceTrim(fullContent),
|
|
20430
|
-
originalLine: currentCommitment.originalStartLine,
|
|
20431
|
-
lineNumber: currentCommitment.startLineNumber,
|
|
20432
|
-
});
|
|
20433
|
-
}
|
|
20432
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
20434
20433
|
// Extract the initial content from the commitment line
|
|
20435
20434
|
const fullRegex = definition.createRegex();
|
|
20436
20435
|
const fullMatch = fullRegex.exec(line.trim());
|
|
20437
20436
|
const initialContent = ((_b = fullMatch === null || fullMatch === void 0 ? void 0 : fullMatch.groups) === null || _b === void 0 ? void 0 : _b.contents) || '';
|
|
20438
20437
|
// Start a new commitment
|
|
20439
20438
|
currentCommitment = {
|
|
20439
|
+
kind: 'known',
|
|
20440
20440
|
type: definition.type,
|
|
20441
20441
|
startLineNumber: i + 1,
|
|
20442
20442
|
originalStartLine: line,
|
|
@@ -20446,52 +20446,90 @@
|
|
|
20446
20446
|
break;
|
|
20447
20447
|
}
|
|
20448
20448
|
}
|
|
20449
|
+
if (foundNewCommitment) {
|
|
20450
|
+
continue;
|
|
20451
|
+
}
|
|
20452
|
+
const unknownCommitmentType = getBookCommitmentLineType(line);
|
|
20453
|
+
if (unknownCommitmentType) {
|
|
20454
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
20455
|
+
currentCommitment = {
|
|
20456
|
+
kind: 'unknown',
|
|
20457
|
+
type: unknownCommitmentType,
|
|
20458
|
+
startLineNumber: i + 1,
|
|
20459
|
+
originalStartLine: line,
|
|
20460
|
+
sourceLines: [line],
|
|
20461
|
+
};
|
|
20462
|
+
continue;
|
|
20463
|
+
}
|
|
20449
20464
|
// Check if this is a horizontal line (ends any current commitment)
|
|
20450
20465
|
const isHorizontalLine = HORIZONTAL_LINE_PATTERN$1.test(line);
|
|
20451
20466
|
if (isHorizontalLine) {
|
|
20452
|
-
|
|
20453
|
-
|
|
20454
|
-
const fullContent = currentCommitment.contentLines.join('\n');
|
|
20455
|
-
commitments.push({
|
|
20456
|
-
type: currentCommitment.type,
|
|
20457
|
-
content: _spaceTrim.spaceTrim(fullContent),
|
|
20458
|
-
originalLine: currentCommitment.originalStartLine,
|
|
20459
|
-
lineNumber: currentCommitment.startLineNumber,
|
|
20460
|
-
});
|
|
20461
|
-
currentCommitment = null;
|
|
20462
|
-
}
|
|
20467
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
20468
|
+
currentCommitment = null;
|
|
20463
20469
|
// Add horizontal line to non-commitment lines
|
|
20464
20470
|
nonCommitmentLines.push(line);
|
|
20465
20471
|
continue;
|
|
20466
20472
|
}
|
|
20467
|
-
|
|
20468
|
-
if (currentCommitment) {
|
|
20469
|
-
// This line belongs to the current commitment
|
|
20470
|
-
currentCommitment.contentLines.push(line);
|
|
20471
|
-
}
|
|
20472
|
-
else {
|
|
20473
|
-
// This line is not part of any commitment
|
|
20474
|
-
nonCommitmentLines.push(line);
|
|
20475
|
-
}
|
|
20476
|
-
}
|
|
20477
|
-
}
|
|
20478
|
-
// Don't forget to save the last commitment if it exists
|
|
20479
|
-
if (currentCommitment) {
|
|
20480
|
-
const fullContent = currentCommitment.contentLines.join('\n');
|
|
20481
|
-
commitments.push({
|
|
20482
|
-
type: currentCommitment.type,
|
|
20483
|
-
content: _spaceTrim.spaceTrim(fullContent),
|
|
20484
|
-
originalLine: currentCommitment.originalStartLine,
|
|
20485
|
-
lineNumber: currentCommitment.startLineNumber,
|
|
20486
|
-
});
|
|
20473
|
+
appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
|
|
20487
20474
|
}
|
|
20475
|
+
appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
|
|
20488
20476
|
return {
|
|
20489
20477
|
agentName,
|
|
20490
20478
|
agentNameLineNumber,
|
|
20491
20479
|
commitments,
|
|
20480
|
+
unknownCommitments,
|
|
20492
20481
|
nonCommitmentLines,
|
|
20493
20482
|
};
|
|
20494
20483
|
}
|
|
20484
|
+
/**
|
|
20485
|
+
* Stores the current known or unknown commitment in its appropriate parsed collection.
|
|
20486
|
+
*
|
|
20487
|
+
* @param currentCommitment - Commitment-like block collected so far.
|
|
20488
|
+
* @param commitments - Parsed registered commitments to append to.
|
|
20489
|
+
* @param unknownCommitments - Parsed unregistered commitments to append to.
|
|
20490
|
+
*
|
|
20491
|
+
* @private internal utility of `parseAgentSourceWithCommitments`
|
|
20492
|
+
*/
|
|
20493
|
+
function appendCurrentCommitment(currentCommitment, commitments, unknownCommitments) {
|
|
20494
|
+
if (!currentCommitment) {
|
|
20495
|
+
return;
|
|
20496
|
+
}
|
|
20497
|
+
if (currentCommitment.kind === 'unknown') {
|
|
20498
|
+
unknownCommitments.push({
|
|
20499
|
+
type: currentCommitment.type,
|
|
20500
|
+
originalLine: currentCommitment.originalStartLine,
|
|
20501
|
+
lineNumber: currentCommitment.startLineNumber,
|
|
20502
|
+
source: _spaceTrim.spaceTrim(currentCommitment.sourceLines.join('\n')),
|
|
20503
|
+
});
|
|
20504
|
+
return;
|
|
20505
|
+
}
|
|
20506
|
+
commitments.push({
|
|
20507
|
+
type: currentCommitment.type,
|
|
20508
|
+
content: _spaceTrim.spaceTrim(currentCommitment.contentLines.join('\n')),
|
|
20509
|
+
originalLine: currentCommitment.originalStartLine,
|
|
20510
|
+
lineNumber: currentCommitment.startLineNumber,
|
|
20511
|
+
});
|
|
20512
|
+
}
|
|
20513
|
+
/**
|
|
20514
|
+
* Adds one source line to the active commitment-like block, or to plain source content when none is active.
|
|
20515
|
+
*
|
|
20516
|
+
* @param currentCommitment - Commitment-like block currently being collected.
|
|
20517
|
+
* @param line - Source line to append.
|
|
20518
|
+
* @param nonCommitmentLines - Plain source lines to append to when no block is active.
|
|
20519
|
+
*
|
|
20520
|
+
* @private internal utility of `parseAgentSourceWithCommitments`
|
|
20521
|
+
*/
|
|
20522
|
+
function appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines) {
|
|
20523
|
+
if (!currentCommitment) {
|
|
20524
|
+
nonCommitmentLines.push(line);
|
|
20525
|
+
return;
|
|
20526
|
+
}
|
|
20527
|
+
if (currentCommitment.kind === 'unknown') {
|
|
20528
|
+
currentCommitment.sourceLines.push(line);
|
|
20529
|
+
return;
|
|
20530
|
+
}
|
|
20531
|
+
currentCommitment.contentLines.push(line);
|
|
20532
|
+
}
|
|
20495
20533
|
|
|
20496
20534
|
/**
|
|
20497
20535
|
* Parses parameters from text using both supported notations:
|
|
@@ -21850,7 +21888,7 @@
|
|
|
21850
21888
|
return agentBookStats.isFile();
|
|
21851
21889
|
}
|
|
21852
21890
|
catch (error) {
|
|
21853
|
-
if (isFileNotFoundError$
|
|
21891
|
+
if (isFileNotFoundError$7(error)) {
|
|
21854
21892
|
return false;
|
|
21855
21893
|
}
|
|
21856
21894
|
throw error;
|
|
@@ -21859,7 +21897,7 @@
|
|
|
21859
21897
|
/**
|
|
21860
21898
|
* Returns true when one filesystem error indicates a missing path.
|
|
21861
21899
|
*/
|
|
21862
|
-
function isFileNotFoundError$
|
|
21900
|
+
function isFileNotFoundError$7(error) {
|
|
21863
21901
|
return Boolean(error &&
|
|
21864
21902
|
typeof error === 'object' &&
|
|
21865
21903
|
'code' in error &&
|
|
@@ -21889,7 +21927,7 @@
|
|
|
21889
21927
|
return await promises.readdir(queuedMessagesDirectoryPath, { withFileTypes: true });
|
|
21890
21928
|
}
|
|
21891
21929
|
catch (error) {
|
|
21892
|
-
if (isFileNotFoundError$
|
|
21930
|
+
if (isFileNotFoundError$6(error)) {
|
|
21893
21931
|
return [];
|
|
21894
21932
|
}
|
|
21895
21933
|
throw error;
|
|
@@ -21910,7 +21948,7 @@
|
|
|
21910
21948
|
/**
|
|
21911
21949
|
* Returns true when an error is a missing-path filesystem error.
|
|
21912
21950
|
*/
|
|
21913
|
-
function isFileNotFoundError$
|
|
21951
|
+
function isFileNotFoundError$6(error) {
|
|
21914
21952
|
return Boolean(error &&
|
|
21915
21953
|
typeof error === 'object' &&
|
|
21916
21954
|
'code' in error &&
|
|
@@ -22388,7 +22426,7 @@
|
|
|
22388
22426
|
lastIndexLockState = await readGitIndexLockState(cwd, options.env);
|
|
22389
22427
|
if ((lastIndexLockState === null || lastIndexLockState === void 0 ? void 0 : lastIndexLockState.isStale) && !isStaleIndexLockRemoved) {
|
|
22390
22428
|
await promises.unlink(lastIndexLockState.path).catch((unlinkError) => {
|
|
22391
|
-
if (isFileNotFoundError$
|
|
22429
|
+
if (isFileNotFoundError$5(unlinkError)) {
|
|
22392
22430
|
return;
|
|
22393
22431
|
}
|
|
22394
22432
|
throw unlinkError;
|
|
@@ -22449,7 +22487,7 @@
|
|
|
22449
22487
|
};
|
|
22450
22488
|
}
|
|
22451
22489
|
catch (error) {
|
|
22452
|
-
if (isFileNotFoundError$
|
|
22490
|
+
if (isFileNotFoundError$5(error)) {
|
|
22453
22491
|
return undefined;
|
|
22454
22492
|
}
|
|
22455
22493
|
throw error;
|
|
@@ -22506,7 +22544,7 @@
|
|
|
22506
22544
|
/**
|
|
22507
22545
|
* Detects missing-file errors while inspecting the lock file.
|
|
22508
22546
|
*/
|
|
22509
|
-
function isFileNotFoundError$
|
|
22547
|
+
function isFileNotFoundError$5(error) {
|
|
22510
22548
|
return Boolean(error &&
|
|
22511
22549
|
typeof error === 'object' &&
|
|
22512
22550
|
'code' in error &&
|
|
@@ -24761,14 +24799,90 @@
|
|
|
24761
24799
|
* without the generated script and the prompt it embeds.
|
|
24762
24800
|
*/
|
|
24763
24801
|
const SCRIPT_EXECUTION_LOG_RAW_OUTPUT_MARKER = '--- raw output ---';
|
|
24802
|
+
/**
|
|
24803
|
+
* Command which terminates the Bash process tree rooted at the running harness.
|
|
24804
|
+
*
|
|
24805
|
+
* Bash's POSIX process IDs differ from Windows process IDs in Git Bash, so the Windows branch resolves the native PID
|
|
24806
|
+
* before delegating to `taskkill`. Unix harnesses run in a dedicated Bash job process group, which can be terminated
|
|
24807
|
+
* with its negative process ID.
|
|
24808
|
+
*/
|
|
24809
|
+
const TERMINATE_BASH_PROCESS_TREE_COMMAND = process.platform === 'win32'
|
|
24810
|
+
? _spaceTrim.spaceTrim(`
|
|
24811
|
+
HARNESS_WINDOWS_PROCESS_ID="$(ps -l -p "$HARNESS_PROCESS_ID" | awk 'NR == 2 { print $4 }')"
|
|
24812
|
+
if [ -n "$HARNESS_WINDOWS_PROCESS_ID" ]; then
|
|
24813
|
+
MSYS_NO_PATHCONV=1 taskkill.exe /PID "$HARNESS_WINDOWS_PROCESS_ID" /T /F > /dev/null 2>&1 || true
|
|
24814
|
+
fi
|
|
24815
|
+
`)
|
|
24816
|
+
: 'kill -TERM -- "-$HARNESS_PROCESS_ID" 2>/dev/null || true';
|
|
24817
|
+
/**
|
|
24818
|
+
* Shell condition that detects whether the Node process which owns the harness is still running.
|
|
24819
|
+
*
|
|
24820
|
+
* Git Bash translates process IDs and command switches, so querying the native Windows PID needs both `tasklist` and
|
|
24821
|
+
* disabled MSYS path conversion there. Unix can use the native `kill -0` process existence check.
|
|
24822
|
+
*/
|
|
24823
|
+
const IS_PARENT_PROCESS_RUNNING_CONDITION = process.platform === 'win32'
|
|
24824
|
+
? '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 }\''
|
|
24825
|
+
: 'kill -0 "$PARENT_CODER_PROCESS_ID" 2>/dev/null';
|
|
24826
|
+
/**
|
|
24827
|
+
* Environment variable that identifies the Node process responsible for a temporary harness shell.
|
|
24828
|
+
*/
|
|
24829
|
+
const PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME = 'PTBK_CODER_PARENT_PROCESS_ID';
|
|
24764
24830
|
/**
|
|
24765
24831
|
* Small bash wrapper that preserves stdout/stderr streams while teeing both into the runtime log file.
|
|
24832
|
+
*
|
|
24833
|
+
* A watcher polls the owning Node process by its PID. If that process exits abruptly, the watcher stops the whole
|
|
24834
|
+
* Bash and harness process tree instead of letting it continue as an orphan.
|
|
24766
24835
|
*/
|
|
24767
24836
|
const LOGGED_BASH_WRAPPER_COMMAND = _spaceTrim.spaceTrim(`
|
|
24837
|
+
PARENT_CODER_PROCESS_ID="\${${PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME}}"
|
|
24838
|
+
unset ${PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME}
|
|
24839
|
+
|
|
24840
|
+
terminate_harness_process_tree() {
|
|
24841
|
+
# Keep the EXIT cleanup intact so the wrapper can also stop its parent-process watcher.
|
|
24842
|
+
trap - HUP INT TERM
|
|
24843
|
+
${TERMINATE_BASH_PROCESS_TREE_COMMAND}
|
|
24844
|
+
}
|
|
24845
|
+
|
|
24846
|
+
is_parent_process_running() {
|
|
24847
|
+
${IS_PARENT_PROCESS_RUNNING_CONDITION}
|
|
24848
|
+
}
|
|
24849
|
+
|
|
24768
24850
|
if [ -n "\${${PTBK_CODER_LOG_FILE_ENV_NAME}:-}" ]; then
|
|
24769
|
-
exec > >(tee -a "
|
|
24851
|
+
exec > >(tee -a "$${PTBK_CODER_LOG_FILE_ENV_NAME}") 2> >(tee -a "$${PTBK_CODER_LOG_FILE_ENV_NAME}" >&2)
|
|
24770
24852
|
fi
|
|
24771
|
-
|
|
24853
|
+
|
|
24854
|
+
watch_parent_process() {
|
|
24855
|
+
trap 'exit 0' HUP INT TERM
|
|
24856
|
+
|
|
24857
|
+
while is_parent_process_running; do
|
|
24858
|
+
sleep 1
|
|
24859
|
+
done
|
|
24860
|
+
|
|
24861
|
+
terminate_harness_process_tree
|
|
24862
|
+
}
|
|
24863
|
+
|
|
24864
|
+
# Background harness jobs need their own process group on Unix so termination cannot reach the parent coder.
|
|
24865
|
+
set -m
|
|
24866
|
+
if ! is_parent_process_running; then
|
|
24867
|
+
exit 1
|
|
24868
|
+
fi
|
|
24869
|
+
bash "$1" &
|
|
24870
|
+
HARNESS_PROCESS_ID=$!
|
|
24871
|
+
|
|
24872
|
+
cleanup_parent_process_watcher() {
|
|
24873
|
+
kill "$PARENT_PROCESS_WATCHER_PID" 2>/dev/null || true
|
|
24874
|
+
wait "$PARENT_PROCESS_WATCHER_PID" 2>/dev/null || true
|
|
24875
|
+
}
|
|
24876
|
+
|
|
24877
|
+
watch_parent_process &
|
|
24878
|
+
PARENT_PROCESS_WATCHER_PID=$!
|
|
24879
|
+
|
|
24880
|
+
trap cleanup_parent_process_watcher EXIT
|
|
24881
|
+
trap terminate_harness_process_tree HUP INT TERM
|
|
24882
|
+
|
|
24883
|
+
wait "$HARNESS_PROCESS_ID"
|
|
24884
|
+
SCRIPT_EXIT_CODE=$?
|
|
24885
|
+
exit "$SCRIPT_EXIT_CODE"
|
|
24772
24886
|
`);
|
|
24773
24887
|
/**
|
|
24774
24888
|
* Shapes one bash invocation that optionally mirrors live script output into a temporary log file.
|
|
@@ -24824,6 +24938,38 @@
|
|
|
24824
24938
|
return scriptPath.toLowerCase().endsWith('.test.sh') ? 'test shell' : 'runner shell';
|
|
24825
24939
|
}
|
|
24826
24940
|
|
|
24941
|
+
/**
|
|
24942
|
+
* Standard streams used by every temporary Bash runner.
|
|
24943
|
+
*/
|
|
24944
|
+
const BASH_PROCESS_STDIO = ['pipe', 'pipe', 'pipe'];
|
|
24945
|
+
/**
|
|
24946
|
+
* Whether the current Node process is running on Windows.
|
|
24947
|
+
*/
|
|
24948
|
+
const IS_WINDOWS$1 = process.platform === 'win32';
|
|
24949
|
+
/**
|
|
24950
|
+
* Starts one temporary Bash script in a process tree owned by the current Node process.
|
|
24951
|
+
*
|
|
24952
|
+
* The wrapper watches the supplied owning process ID. When that process exits abruptly, the wrapper terminates every
|
|
24953
|
+
* nested shell and harness process instead of leaving it orphaned.
|
|
24954
|
+
*
|
|
24955
|
+
* @private internal utility of the coding prompt runner
|
|
24956
|
+
*/
|
|
24957
|
+
function $spawnLoggedBashScript(options) {
|
|
24958
|
+
var _a;
|
|
24959
|
+
const bashExecution = buildLoggedBashExecution(options.scriptPath, options.logPath);
|
|
24960
|
+
const parentProcessId = (_a = options.parentProcessId) !== null && _a !== void 0 ? _a : process.pid;
|
|
24961
|
+
return child_process.spawn('bash', bashExecution.args, {
|
|
24962
|
+
detached: !IS_WINDOWS$1,
|
|
24963
|
+
env: {
|
|
24964
|
+
...process.env,
|
|
24965
|
+
...bashExecution.env,
|
|
24966
|
+
[PTBK_CODER_PARENT_PROCESS_ID_ENV_NAME]: parentProcessId.toString(),
|
|
24967
|
+
},
|
|
24968
|
+
stdio: BASH_PROCESS_STDIO,
|
|
24969
|
+
windowsHide: true,
|
|
24970
|
+
});
|
|
24971
|
+
}
|
|
24972
|
+
|
|
24827
24973
|
/**
|
|
24828
24974
|
* Prints one live shell output chunk to the terminal when console mirroring is enabled.
|
|
24829
24975
|
*/
|
|
@@ -24846,12 +24992,12 @@
|
|
|
24846
24992
|
async function runBashScriptWithOutput(options) {
|
|
24847
24993
|
var _a;
|
|
24848
24994
|
await appendScriptExecutionLogStart(options);
|
|
24849
|
-
const bashExecution = buildLoggedBashExecution(options.scriptPath, options.logPath);
|
|
24850
24995
|
const scriptPathPosix = toPosixPath(options.scriptPath);
|
|
24851
24996
|
const shouldPrintLiveOutput = (_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true;
|
|
24852
24997
|
return await new Promise((resolve, reject) => {
|
|
24853
|
-
const commandProcess =
|
|
24854
|
-
|
|
24998
|
+
const commandProcess = $spawnLoggedBashScript({
|
|
24999
|
+
scriptPath: options.scriptPath,
|
|
25000
|
+
logPath: options.logPath,
|
|
24855
25001
|
});
|
|
24856
25002
|
let output = '';
|
|
24857
25003
|
let settled = false;
|
|
@@ -24910,8 +25056,9 @@
|
|
|
24910
25056
|
const failure = new Error(_spaceTrim.spaceTrim(output) || `Command "bash ${scriptPathPosix}" exited with code ${code}`);
|
|
24911
25057
|
settleWithLog(`failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}`, () => reject(failure), failure);
|
|
24912
25058
|
};
|
|
25059
|
+
// Wait for `close`, not only `exit`, because the Bash wrapper can still be flushing its tee process
|
|
25060
|
+
// substitutions after the direct shell exits.
|
|
24913
25061
|
commandProcess.on('close', handleExit);
|
|
24914
|
-
commandProcess.on('exit', handleExit);
|
|
24915
25062
|
commandProcess.on('disconnect', () => {
|
|
24916
25063
|
const failure = new Error(`Command "bash ${scriptPathPosix}" disconnected`);
|
|
24917
25064
|
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
@@ -25772,6 +25919,35 @@
|
|
|
25772
25919
|
error.message.includes('bin/node'));
|
|
25773
25920
|
}
|
|
25774
25921
|
|
|
25922
|
+
/**
|
|
25923
|
+
* Whether the current coder process runs on Windows.
|
|
25924
|
+
*/
|
|
25925
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
25926
|
+
/**
|
|
25927
|
+
* Stops one active temporary Bash shell together with the harness process tree it owns.
|
|
25928
|
+
*
|
|
25929
|
+
* Unix sends `SIGTERM` to the wrapper so its shell trap terminates the separately grouped harness job. Windows does
|
|
25930
|
+
* not reliably deliver that signal to Bash, so the native `taskkill` command terminates the direct shell tree instead.
|
|
25931
|
+
*
|
|
25932
|
+
* @private internal utility of the coding prompt runner
|
|
25933
|
+
*/
|
|
25934
|
+
function $terminateLoggedBashProcessTree(commandProcess) {
|
|
25935
|
+
if (commandProcess.exitCode !== null || commandProcess.signalCode !== null) {
|
|
25936
|
+
return;
|
|
25937
|
+
}
|
|
25938
|
+
if (!IS_WINDOWS) {
|
|
25939
|
+
commandProcess.kill('SIGTERM');
|
|
25940
|
+
return;
|
|
25941
|
+
}
|
|
25942
|
+
if (!commandProcess.pid) {
|
|
25943
|
+
return;
|
|
25944
|
+
}
|
|
25945
|
+
child_process.spawnSync('taskkill.exe', ['/PID', commandProcess.pid.toString(), '/T', '/F'], {
|
|
25946
|
+
stdio: 'ignore',
|
|
25947
|
+
windowsHide: true,
|
|
25948
|
+
});
|
|
25949
|
+
}
|
|
25950
|
+
|
|
25775
25951
|
/**
|
|
25776
25952
|
* Maximum number of output characters included in thrown error messages.
|
|
25777
25953
|
*/
|
|
@@ -25814,15 +25990,16 @@
|
|
|
25814
25990
|
const scriptPathPosix = toPosixPath(scriptPath);
|
|
25815
25991
|
const shouldPrintLiveOutput = (_a = options.shouldPrintLiveOutput) !== null && _a !== void 0 ? _a : true;
|
|
25816
25992
|
await appendScriptExecutionLogStart(options);
|
|
25817
|
-
const bashExecution = buildLoggedBashExecution(scriptPath, options.logPath);
|
|
25818
25993
|
return await new Promise((resolve, reject) => {
|
|
25819
|
-
const commandProcess =
|
|
25820
|
-
|
|
25994
|
+
const commandProcess = $spawnLoggedBashScript({
|
|
25995
|
+
scriptPath,
|
|
25996
|
+
logPath: options.logPath,
|
|
25821
25997
|
});
|
|
25822
25998
|
let stdoutBuffer = '';
|
|
25823
25999
|
let stderrBuffer = '';
|
|
25824
26000
|
let fullOutput = '';
|
|
25825
26001
|
let markerSeen = false;
|
|
26002
|
+
let isCompletedAfterIdleTimeout = false;
|
|
25826
26003
|
let idleTimer;
|
|
25827
26004
|
let settled = false;
|
|
25828
26005
|
let isSettling = false;
|
|
@@ -25864,15 +26041,16 @@
|
|
|
25864
26041
|
});
|
|
25865
26042
|
};
|
|
25866
26043
|
/**
|
|
25867
|
-
*
|
|
26044
|
+
* Stops a marker-completed process tree after its trailing output becomes idle.
|
|
25868
26045
|
*/
|
|
25869
26046
|
const finishAfterIdleTimeout = () => {
|
|
25870
|
-
|
|
26047
|
+
isCompletedAfterIdleTimeout = true;
|
|
26048
|
+
idleTimer = undefined;
|
|
25871
26049
|
try {
|
|
25872
|
-
commandProcess
|
|
26050
|
+
$terminateLoggedBashProcessTree(commandProcess);
|
|
25873
26051
|
}
|
|
25874
26052
|
catch (_a) {
|
|
25875
|
-
//
|
|
26053
|
+
// The close handler below still settles normally when Bash already exited before the idle timer fired.
|
|
25876
26054
|
}
|
|
25877
26055
|
};
|
|
25878
26056
|
/**
|
|
@@ -25931,7 +26109,11 @@
|
|
|
25931
26109
|
const failure = code === 0 || markerSeen
|
|
25932
26110
|
? undefined
|
|
25933
26111
|
: new Error(buildCommandFailureMessage(scriptPathPosix, code, fullOutput));
|
|
25934
|
-
const status =
|
|
26112
|
+
const status = isCompletedAfterIdleTimeout
|
|
26113
|
+
? 'completed after idle timeout'
|
|
26114
|
+
: failure
|
|
26115
|
+
? `failed with exit code ${code !== null && code !== void 0 ? code : 'unknown'}`
|
|
26116
|
+
: 'succeeded';
|
|
25935
26117
|
settleWithLog(status, () => {
|
|
25936
26118
|
if (!failure) {
|
|
25937
26119
|
resolve(fullOutput);
|
|
@@ -25940,8 +26122,9 @@
|
|
|
25940
26122
|
reject(failure);
|
|
25941
26123
|
});
|
|
25942
26124
|
};
|
|
26125
|
+
// Wait for `close`, not only `exit`, because the Bash wrapper can still be flushing its tee process
|
|
26126
|
+
// substitutions after the direct shell exits.
|
|
25943
26127
|
commandProcess.on('close', handleExit);
|
|
25944
|
-
commandProcess.on('exit', handleExit);
|
|
25945
26128
|
commandProcess.on('disconnect', () => {
|
|
25946
26129
|
const failure = new Error(buildCommandFailureMessage(scriptPathPosix, null, fullOutput));
|
|
25947
26130
|
settleWithLog('failed after disconnect', () => reject(failure), failure);
|
|
@@ -29437,7 +29620,7 @@
|
|
|
29437
29620
|
return crypto.createHash('sha1').update(content).digest('hex');
|
|
29438
29621
|
}
|
|
29439
29622
|
catch (error) {
|
|
29440
|
-
if (isFileNotFoundError$
|
|
29623
|
+
if (isFileNotFoundError$4(error)) {
|
|
29441
29624
|
return null;
|
|
29442
29625
|
}
|
|
29443
29626
|
throw error;
|
|
@@ -29452,7 +29635,7 @@
|
|
|
29452
29635
|
/**
|
|
29453
29636
|
* Returns true when an error is a missing-file filesystem error.
|
|
29454
29637
|
*/
|
|
29455
|
-
function isFileNotFoundError$
|
|
29638
|
+
function isFileNotFoundError$4(error) {
|
|
29456
29639
|
return Boolean(error &&
|
|
29457
29640
|
typeof error === 'object' &&
|
|
29458
29641
|
'code' in error &&
|
|
@@ -30445,7 +30628,7 @@
|
|
|
30445
30628
|
- 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.
|
|
30446
30629
|
- 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.
|
|
30447
30630
|
- A project can be a git repository — you can run \`git init\` inside a project folder and commit your work there.
|
|
30448
|
-
- Do not touch anything outside the \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory
|
|
30631
|
+
- Do not touch anything outside the \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory beyond the file changes allowed at the top of this prompt.
|
|
30449
30632
|
|
|
30450
30633
|
${block(buildProjectReferenceInstructions(projectsUrlPath))}
|
|
30451
30634
|
${block(buildProjectRuntimeInstructions(options.projectRuntimeApi))}
|
|
@@ -30501,55 +30684,166 @@
|
|
|
30501
30684
|
}
|
|
30502
30685
|
|
|
30503
30686
|
/**
|
|
30504
|
-
*
|
|
30687
|
+
* Milliseconds in one second.
|
|
30688
|
+
*
|
|
30689
|
+
* @private internal timeout-chat constant
|
|
30690
|
+
*/
|
|
30691
|
+
const SECOND_IN_MILLISECONDS = 1000;
|
|
30692
|
+
/**
|
|
30693
|
+
* Seconds in one minute.
|
|
30694
|
+
*
|
|
30695
|
+
* @private internal timeout-chat constant
|
|
30696
|
+
*/
|
|
30697
|
+
const MINUTE_IN_SECONDS = 60;
|
|
30698
|
+
/**
|
|
30699
|
+
* Seconds in one hour.
|
|
30700
|
+
*
|
|
30701
|
+
* @private internal timeout-chat constant
|
|
30702
|
+
*/
|
|
30703
|
+
const HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS;
|
|
30704
|
+
/**
|
|
30705
|
+
* Seconds in one day.
|
|
30706
|
+
*
|
|
30707
|
+
* @private internal timeout-chat constant
|
|
30708
|
+
*/
|
|
30709
|
+
const HOURS_IN_DAY = 24;
|
|
30710
|
+
/**
|
|
30711
|
+
* Seconds in one day.
|
|
30712
|
+
*
|
|
30713
|
+
* @private internal timeout-chat constant
|
|
30505
30714
|
*/
|
|
30715
|
+
const DAY_IN_SECONDS = HOURS_IN_DAY * HOUR_IN_SECONDS;
|
|
30506
30716
|
/**
|
|
30507
|
-
*
|
|
30717
|
+
* Converts timeout duration into natural language sentence fragments.
|
|
30718
|
+
*
|
|
30719
|
+
* Shared by every timeout surface: the chat chips, the goal-chat planned messages of the Agents
|
|
30720
|
+
* Server, and the planned-message prompt section of the agent-folder runner.
|
|
30721
|
+
*
|
|
30722
|
+
* @param milliseconds - Duration or repeat interval in milliseconds.
|
|
30723
|
+
* @returns Label such as `5 minutes` or `1 hour 30 minutes`.
|
|
30724
|
+
*
|
|
30725
|
+
* @private internal utility of `<Chat/>` and the Agents Server planned messages
|
|
30508
30726
|
*/
|
|
30509
|
-
|
|
30727
|
+
function formatTimeoutDurationHuman(milliseconds) {
|
|
30728
|
+
const normalizedMilliseconds = Math.max(0, Math.floor(milliseconds));
|
|
30729
|
+
const totalSeconds = Math.max(1, Math.floor(normalizedMilliseconds / SECOND_IN_MILLISECONDS));
|
|
30730
|
+
if (totalSeconds < MINUTE_IN_SECONDS) {
|
|
30731
|
+
return formatTimeoutUnit(totalSeconds, 'second');
|
|
30732
|
+
}
|
|
30733
|
+
if (totalSeconds < HOUR_IN_SECONDS) {
|
|
30734
|
+
const roundedMinutes = Math.max(1, Math.round(totalSeconds / MINUTE_IN_SECONDS));
|
|
30735
|
+
return formatTimeoutUnit(roundedMinutes, 'minute');
|
|
30736
|
+
}
|
|
30737
|
+
if (totalSeconds < DAY_IN_SECONDS) {
|
|
30738
|
+
const hours = Math.floor(totalSeconds / HOUR_IN_SECONDS);
|
|
30739
|
+
const minutes = Math.floor((totalSeconds % HOUR_IN_SECONDS) / MINUTE_IN_SECONDS);
|
|
30740
|
+
if (minutes === 0) {
|
|
30741
|
+
return formatTimeoutUnit(hours, 'hour');
|
|
30742
|
+
}
|
|
30743
|
+
return `${formatTimeoutUnit(hours, 'hour')} ${formatTimeoutUnit(minutes, 'minute')}`;
|
|
30744
|
+
}
|
|
30745
|
+
const days = Math.floor(totalSeconds / DAY_IN_SECONDS);
|
|
30746
|
+
const hours = Math.floor((totalSeconds % DAY_IN_SECONDS) / HOUR_IN_SECONDS);
|
|
30747
|
+
if (hours === 0) {
|
|
30748
|
+
return formatTimeoutUnit(days, 'day');
|
|
30749
|
+
}
|
|
30750
|
+
return `${formatTimeoutUnit(days, 'day')} ${formatTimeoutUnit(hours, 'hour')}`;
|
|
30751
|
+
}
|
|
30752
|
+
/**
|
|
30753
|
+
* Formats one pluralized timeout unit.
|
|
30754
|
+
*
|
|
30755
|
+
* @private internal timeout-chat helper
|
|
30756
|
+
*/
|
|
30757
|
+
function formatTimeoutUnit(value, unit) {
|
|
30758
|
+
return `${value} ${unit}${value === 1 ? '' : 's'}`;
|
|
30759
|
+
}
|
|
30760
|
+
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
30510
30761
|
|
|
30511
30762
|
/**
|
|
30512
30763
|
* Builds the planned-message instructions available to an Agents Server-managed coding agent.
|
|
30513
30764
|
*
|
|
30514
|
-
* Planned messages always target the agent's singleton goal chat, regardless of the chat in which
|
|
30515
|
-
*
|
|
30765
|
+
* Planned messages always target the agent's singleton goal chat, regardless of the chat in which the
|
|
30766
|
+
* wake-up is planned, and they repeat like `setInterval` until they are cancelled. The sidecar file is
|
|
30767
|
+
* the only channel that changes them, so an answer that merely claims a follow-up was planned changes
|
|
30768
|
+
* nothing — and an answer that changes nothing keeps the current plan running.
|
|
30769
|
+
*
|
|
30770
|
+
* @param sidecar - Sidecar prepared by the Agents Server for the answered message.
|
|
30771
|
+
* @returns Prompt section, or an empty string outside Agents Server-managed runs.
|
|
30516
30772
|
*/
|
|
30517
|
-
function buildAgentGoalChatPromptSection(
|
|
30518
|
-
if (!
|
|
30773
|
+
function buildAgentGoalChatPromptSection(sidecar) {
|
|
30774
|
+
if (!sidecar) {
|
|
30519
30775
|
return '';
|
|
30520
30776
|
}
|
|
30521
|
-
return _spaceTrim.spaceTrim(`
|
|
30522
|
-
|
|
30777
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
30778
|
+
## Planned goal-chat messages
|
|
30523
30779
|
|
|
30524
|
-
|
|
30780
|
+
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.
|
|
30525
30781
|
|
|
30526
|
-
|
|
30527
|
-
- 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.
|
|
30528
|
-
- Use \`cancel_timeout\` with the returned \`timeoutId\` when a planned message is no longer useful.
|
|
30529
|
-
- 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.
|
|
30782
|
+
${block(buildCurrentPlannedMessagesLines(sidecar.currentPlannedMessages))}
|
|
30530
30783
|
|
|
30531
|
-
|
|
30784
|
+
Editing \`${sidecar.relativeSidecarPath}\` is the **only** way to change what wakes you. Writing in your answer that you scheduled something does not schedule anything.
|
|
30532
30785
|
|
|
30533
|
-
|
|
30534
|
-
|
|
30535
|
-
|
|
30536
|
-
|
|
30537
|
-
|
|
30538
|
-
|
|
30786
|
+
- **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.
|
|
30787
|
+
- 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.
|
|
30788
|
+
- 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.
|
|
30789
|
+
- When your goal no longer needs a listed message at all, cancel it without planning a replacement.
|
|
30790
|
+
- Never edit \`version\`, \`agentPermanentId\`, or \`currentPlannedMessages\`.
|
|
30791
|
+
- The Agents Server applies every command once your answer is finished, and each repetition appears in the goal chat and invokes you there.
|
|
30792
|
+
- 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.
|
|
30793
|
+
`);
|
|
30794
|
+
}
|
|
30795
|
+
/**
|
|
30796
|
+
* Renders the already planned messages so the agent can compare them with its goal.
|
|
30797
|
+
*
|
|
30798
|
+
* @param currentPlannedMessages - Planned messages prepared by the Agents Server.
|
|
30799
|
+
* @returns Markdown list, or a sentence stating that nothing is planned yet.
|
|
30800
|
+
*
|
|
30801
|
+
* @private function of `buildAgentGoalChatPromptSection`
|
|
30802
|
+
*/
|
|
30803
|
+
function buildCurrentPlannedMessagesLines(currentPlannedMessages) {
|
|
30804
|
+
if (currentPlannedMessages.length === 0) {
|
|
30805
|
+
return 'You currently have no planned messages waiting.';
|
|
30806
|
+
}
|
|
30807
|
+
const plannedMessageLines = currentPlannedMessages.map(createCurrentPlannedMessageLine);
|
|
30808
|
+
return _spaceTrim.spaceTrim((block) => `
|
|
30809
|
+
These planned messages are already waiting for you, so keep them unless they stopped matching your goal:
|
|
30539
30810
|
|
|
30540
|
-
|
|
30541
|
-
|
|
30542
|
-
|
|
30543
|
-
|
|
30544
|
-
|
|
30811
|
+
${block(plannedMessageLines.join('\n'))}
|
|
30812
|
+
`);
|
|
30813
|
+
}
|
|
30814
|
+
/**
|
|
30815
|
+
* Renders one already planned message with the schedule the agent has to compare with its goal.
|
|
30816
|
+
*
|
|
30817
|
+
* @param plannedMessage - One planned message prepared by the Agents Server.
|
|
30818
|
+
* @returns Markdown list item.
|
|
30819
|
+
*
|
|
30820
|
+
* @private function of `buildAgentGoalChatPromptSection`
|
|
30821
|
+
*/
|
|
30822
|
+
function createCurrentPlannedMessageLine(plannedMessage) {
|
|
30823
|
+
var _a;
|
|
30824
|
+
const message = ((_a = plannedMessage.message) === null || _a === void 0 ? void 0 : _a.trim()) || 'Continue working towards the current goal.';
|
|
30825
|
+
const schedule = plannedMessage.intervalMs
|
|
30826
|
+
? `repeats every ${formatTimeoutDurationHuman(plannedMessage.intervalMs)}`
|
|
30827
|
+
: `wakes you once at ${plannedMessage.dueAt}`;
|
|
30828
|
+
return `- \`${plannedMessage.timeoutId}\` ${schedule}: ${message}`;
|
|
30829
|
+
}
|
|
30545
30830
|
|
|
30546
|
-
|
|
30547
|
-
|
|
30548
|
-
|
|
30549
|
-
|
|
30550
|
-
|
|
30551
|
-
|
|
30552
|
-
|
|
30831
|
+
/**
|
|
30832
|
+
* Creates the stable file-system safe base name that belongs to one queued `.book` message.
|
|
30833
|
+
*
|
|
30834
|
+
* Every sidecar the Agents Server prepares next to a queued message (TEAM workspaces, planned-message
|
|
30835
|
+
* files, ...) derives its own name from this one normalization, so a sidecar can always be found again
|
|
30836
|
+
* from the message file name alone.
|
|
30837
|
+
*
|
|
30838
|
+
* @param messageFileName - File name of the queued message, with or without directories.
|
|
30839
|
+
* @returns Normalized base name usable as a directory or file name.
|
|
30840
|
+
*
|
|
30841
|
+
* @private internal convention shared by the Agents Server and agent-folder runner
|
|
30842
|
+
*/
|
|
30843
|
+
function createAgentMessageSidecarBaseName(messageFileName) {
|
|
30844
|
+
const rawBaseName = path.basename(messageFileName).replace(/\.book$/iu, '');
|
|
30845
|
+
const normalizedBaseName = rawBaseName.replace(/[^A-Za-z0-9._-]+/gu, '-').replace(/^[._-]+|[._-]+$/gu, '');
|
|
30846
|
+
return normalizedBaseName || 'message';
|
|
30553
30847
|
}
|
|
30554
30848
|
|
|
30555
30849
|
// Note: [💞] This file defines the shared TEAM workspace convention rather than one standalone entity.
|
|
@@ -30583,9 +30877,7 @@
|
|
|
30583
30877
|
* @private internal convention shared by the Agents Server and agent-folder runner
|
|
30584
30878
|
*/
|
|
30585
30879
|
function createAgentTeamConversationWorkspaceDirectoryName(messageFileName) {
|
|
30586
|
-
|
|
30587
|
-
const normalizedBaseName = rawBaseName.replace(/[^A-Za-z0-9._-]+/gu, '-').replace(/^[._-]+|[._-]+$/gu, '');
|
|
30588
|
-
return normalizedBaseName || 'message';
|
|
30880
|
+
return createAgentMessageSidecarBaseName(messageFileName);
|
|
30589
30881
|
}
|
|
30590
30882
|
/**
|
|
30591
30883
|
* Creates the relative active workspace path for one queued message.
|
|
@@ -30655,8 +30947,8 @@
|
|
|
30655
30947
|
return '';
|
|
30656
30948
|
}
|
|
30657
30949
|
const teammateSections = workspace.manifest.teammates.map((teammate) => {
|
|
30658
|
-
const sourcePath = toPromptPath(path.join(workspace.relativeWorkspacePath, AGENT_TEAMMATE_SOURCES_DIRECTORY_NAME, teammate.sourceFileName));
|
|
30659
|
-
const transcriptPath = toPromptPath(path.join(workspace.relativeWorkspacePath, `${teammate.permanentId}--01.book`));
|
|
30950
|
+
const sourcePath = toPromptPath$1(path.join(workspace.relativeWorkspacePath, AGENT_TEAMMATE_SOURCES_DIRECTORY_NAME, teammate.sourceFileName));
|
|
30951
|
+
const transcriptPath = toPromptPath$1(path.join(workspace.relativeWorkspacePath, `${teammate.permanentId}--01.book`));
|
|
30660
30952
|
const instructions = teammate.instructions.trim() || 'No additional TEAM instructions were provided.';
|
|
30661
30953
|
return _spaceTrim.spaceTrim(`
|
|
30662
30954
|
- ${teammate.agentName}
|
|
@@ -30674,7 +30966,7 @@
|
|
|
30674
30966
|
|
|
30675
30967
|
- 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.
|
|
30676
30968
|
- The primary agent remains responsible for the final user-facing \`MESSAGE @Agent\` answer.
|
|
30677
|
-
- 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)}\`.
|
|
30969
|
+
- 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)}\`.
|
|
30678
30970
|
- Name each transcript \`<teammate permanent id>--<sequence>.book\`, for example \`${workspace.manifest.teammates[0].permanentId}--01.book\`.
|
|
30679
30971
|
- 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.
|
|
30680
30972
|
`);
|
|
@@ -30682,7 +30974,7 @@
|
|
|
30682
30974
|
/**
|
|
30683
30975
|
* Converts a filesystem-relative path into the portable path notation used in prompts.
|
|
30684
30976
|
*/
|
|
30685
|
-
function toPromptPath(path) {
|
|
30977
|
+
function toPromptPath$1(path) {
|
|
30686
30978
|
return path.replace(/\\/gu, '/');
|
|
30687
30979
|
}
|
|
30688
30980
|
|
|
@@ -30695,7 +30987,7 @@
|
|
|
30695
30987
|
|
|
30696
30988
|
- 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\`.
|
|
30697
30989
|
- Only change the queued message file by appending one new \`MESSAGE @Agent\` block
|
|
30698
|
-
${block(buildAllowedFileChangesPromptLine(options
|
|
30990
|
+
${block(buildAllowedFileChangesPromptLine(options))}
|
|
30699
30991
|
|
|
30700
30992
|
## Rules for the answering
|
|
30701
30993
|
|
|
@@ -30731,7 +31023,7 @@
|
|
|
30731
31023
|
|
|
30732
31024
|
- 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.
|
|
30733
31025
|
|
|
30734
|
-
${block(buildAgentGoalChatPromptSection(options.
|
|
31026
|
+
${block(buildAgentGoalChatPromptSection(options.plannedMessagesSidecar))}
|
|
30735
31027
|
|
|
30736
31028
|
${block(buildAgentProjectsPromptSection(options))}
|
|
30737
31029
|
|
|
@@ -30745,11 +31037,30 @@
|
|
|
30745
31037
|
/**
|
|
30746
31038
|
* Explains the exact files that one coding harness may change for a user turn.
|
|
30747
31039
|
*/
|
|
30748
|
-
function buildAllowedFileChangesPromptLine(
|
|
30749
|
-
|
|
30750
|
-
|
|
31040
|
+
function buildAllowedFileChangesPromptLine(options) {
|
|
31041
|
+
const allowedFileChanges = [`files inside your own \`${AGENT_PROJECTS_DIRECTORY_PATH}/\` directory`];
|
|
31042
|
+
if (options.teamWorkspace) {
|
|
31043
|
+
allowedFileChanges.push(`new consultation transcripts inside \`${toPromptPath(options.teamWorkspace.relativeWorkspacePath)}\``);
|
|
31044
|
+
}
|
|
31045
|
+
if (options.plannedMessagesSidecar) {
|
|
31046
|
+
allowedFileChanges.push(`the \`commands\` array of \`${toPromptPath(options.plannedMessagesSidecar.relativeSidecarPath)}\``);
|
|
31047
|
+
}
|
|
31048
|
+
return `- Do not modify any other file in the repository, except ${formatAllowedFileChanges(allowedFileChanges)}`;
|
|
31049
|
+
}
|
|
31050
|
+
/**
|
|
31051
|
+
* Joins the allowed file-change phrases into one readable enumeration.
|
|
31052
|
+
*/
|
|
31053
|
+
function formatAllowedFileChanges(allowedFileChanges) {
|
|
31054
|
+
if (allowedFileChanges.length === 1) {
|
|
31055
|
+
return allowedFileChanges[0];
|
|
30751
31056
|
}
|
|
30752
|
-
return
|
|
31057
|
+
return `${allowedFileChanges.slice(0, -1).join(', ')} and ${allowedFileChanges[allowedFileChanges.length - 1]}`;
|
|
31058
|
+
}
|
|
31059
|
+
/**
|
|
31060
|
+
* Converts a filesystem-relative path into the portable path notation used in prompts.
|
|
31061
|
+
*/
|
|
31062
|
+
function toPromptPath(path) {
|
|
31063
|
+
return path.replace(/\\/gu, '/');
|
|
30753
31064
|
}
|
|
30754
31065
|
|
|
30755
31066
|
var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpful assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n```json\n{availableModels}\n```\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpful assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
|
|
@@ -36811,7 +37122,8 @@
|
|
|
36811
37122
|
requirements = await importReferencedFiles(requirements);
|
|
36812
37123
|
requirements = appendMcpServers(requirements, agentSource);
|
|
36813
37124
|
requirements = appendNonCommitmentContent(requirements, parseResult);
|
|
36814
|
-
|
|
37125
|
+
requirements = appendExampleInteractions(requirements, parseResult);
|
|
37126
|
+
return appendUnknownCommitmentContent(requirements, parseResult);
|
|
36815
37127
|
}
|
|
36816
37128
|
/**
|
|
36817
37129
|
* Imports text files referenced by IMPORT commitments and appends their transformed content to the system message.
|
|
@@ -36933,6 +37245,36 @@
|
|
|
36933
37245
|
}
|
|
36934
37246
|
return appendSystemMessageSection(requirements, nonCommitmentContent);
|
|
36935
37247
|
}
|
|
37248
|
+
/**
|
|
37249
|
+
* Appends unknown commitment blocks as final extra context without applying commitment side effects.
|
|
37250
|
+
*
|
|
37251
|
+
* @param requirements - Current requirements snapshot.
|
|
37252
|
+
* @param parseResult - Parsed source including unknown commitment blocks.
|
|
37253
|
+
* @returns Requirements with unknown commitment context appended at the end of the system message.
|
|
37254
|
+
*
|
|
37255
|
+
* @private internal utility of `augmentAgentModelRequirementsFromSource`
|
|
37256
|
+
*/
|
|
37257
|
+
function appendUnknownCommitmentContent(requirements, parseResult) {
|
|
37258
|
+
const unknownCommitmentContent = getUnknownCommitmentContent(parseResult);
|
|
37259
|
+
if (!unknownCommitmentContent) {
|
|
37260
|
+
return requirements;
|
|
37261
|
+
}
|
|
37262
|
+
return appendSystemMessageSection(requirements, unknownCommitmentContent);
|
|
37263
|
+
}
|
|
37264
|
+
/**
|
|
37265
|
+
* Joins unknown commitment blocks into their final extra-context representation.
|
|
37266
|
+
*
|
|
37267
|
+
* @param parseResult - Parsed source including unknown commitment blocks.
|
|
37268
|
+
* @returns Unknown commitment source blocks in their original order.
|
|
37269
|
+
*
|
|
37270
|
+
* @private internal utility of `appendUnknownCommitmentContent`
|
|
37271
|
+
*/
|
|
37272
|
+
function getUnknownCommitmentContent(parseResult) {
|
|
37273
|
+
return parseResult.unknownCommitments
|
|
37274
|
+
.map((commitment) => commitment.source)
|
|
37275
|
+
.filter(Boolean)
|
|
37276
|
+
.join('\n\n');
|
|
37277
|
+
}
|
|
36936
37278
|
/**
|
|
36937
37279
|
* Collects plain-text lines that were not parsed as commitments and should still become part of the final system message.
|
|
36938
37280
|
*
|
|
@@ -37472,12 +37814,12 @@
|
|
|
37472
37814
|
await promises.rm(finishedWorkspacePath, { recursive: true, force: true });
|
|
37473
37815
|
await promises.mkdir(finishedWorkspacePath, { recursive: true });
|
|
37474
37816
|
const relativePaths = [
|
|
37475
|
-
toPortablePath$
|
|
37817
|
+
toPortablePath$2(path.join(finishedRelativeWorkspacePath, AGENT_TEAM_CONVERSATION_MANIFEST_FILE_NAME)),
|
|
37476
37818
|
];
|
|
37477
37819
|
await promises.rename(activeManifestPath, path.join(finishedWorkspacePath, AGENT_TEAM_CONVERSATION_MANIFEST_FILE_NAME));
|
|
37478
37820
|
for (const transcriptFileName of transcriptFileNames) {
|
|
37479
37821
|
await promises.rename(path.join(activeWorkspacePath, transcriptFileName), path.join(finishedWorkspacePath, transcriptFileName));
|
|
37480
|
-
relativePaths.push(toPortablePath$
|
|
37822
|
+
relativePaths.push(toPortablePath$2(path.join(finishedRelativeWorkspacePath, transcriptFileName)));
|
|
37481
37823
|
}
|
|
37482
37824
|
await promises.rm(activeWorkspacePath, { recursive: true, force: true });
|
|
37483
37825
|
return { relativePaths };
|
|
@@ -37494,7 +37836,7 @@
|
|
|
37494
37836
|
.sort((firstFileName, secondFileName) => firstFileName.localeCompare(secondFileName));
|
|
37495
37837
|
}
|
|
37496
37838
|
catch (error) {
|
|
37497
|
-
if (isFileNotFoundError$
|
|
37839
|
+
if (isFileNotFoundError$3(error)) {
|
|
37498
37840
|
return [];
|
|
37499
37841
|
}
|
|
37500
37842
|
throw error;
|
|
@@ -37509,7 +37851,7 @@
|
|
|
37509
37851
|
return true;
|
|
37510
37852
|
}
|
|
37511
37853
|
catch (error) {
|
|
37512
|
-
if (isFileNotFoundError$
|
|
37854
|
+
if (isFileNotFoundError$3(error)) {
|
|
37513
37855
|
return false;
|
|
37514
37856
|
}
|
|
37515
37857
|
throw error;
|
|
@@ -37518,11 +37860,204 @@
|
|
|
37518
37860
|
/**
|
|
37519
37861
|
* Converts a filesystem-relative path into a portable Git path.
|
|
37520
37862
|
*/
|
|
37863
|
+
function toPortablePath$2(path) {
|
|
37864
|
+
return path.replace(/\\/gu, '/');
|
|
37865
|
+
}
|
|
37866
|
+
/**
|
|
37867
|
+
* Returns true when one filesystem error indicates a missing path.
|
|
37868
|
+
*/
|
|
37869
|
+
function isFileNotFoundError$3(error) {
|
|
37870
|
+
return Boolean(error &&
|
|
37871
|
+
typeof error === 'object' &&
|
|
37872
|
+
'code' in error &&
|
|
37873
|
+
(error.code === 'ENOENT' || error.code === 'ENOTDIR'));
|
|
37874
|
+
}
|
|
37875
|
+
|
|
37876
|
+
// Note: [💞] This file defines the shared planned-message sidecar convention rather than one standalone entity.
|
|
37877
|
+
/**
|
|
37878
|
+
* Relative directory holding the planned-message sidecar of each queued message.
|
|
37879
|
+
*
|
|
37880
|
+
* @private internal convention shared by the Agents Server and agent-folder runner
|
|
37881
|
+
*/
|
|
37882
|
+
const AGENT_PLANNED_MESSAGES_DIRECTORY_PATH = path.join(AGENT_MESSAGES_DIRECTORY_PATH, 'planned');
|
|
37883
|
+
/**
|
|
37884
|
+
* Command actions an agent can request from its planned-message sidecar.
|
|
37885
|
+
*
|
|
37886
|
+
* @private internal convention shared by the Agents Server and agent-folder runner
|
|
37887
|
+
*/
|
|
37888
|
+
const AGENT_PLANNED_MESSAGE_COMMAND_ACTIONS = ['set', 'cancel'];
|
|
37889
|
+
/**
|
|
37890
|
+
* Creates the relative planned-message sidecar path of one queued message.
|
|
37891
|
+
*
|
|
37892
|
+
* @param messageFileName - File name of the queued `.book` message.
|
|
37893
|
+
* @returns Relative path of the sidecar inside the agent folder.
|
|
37894
|
+
*
|
|
37895
|
+
* @private internal convention shared by the Agents Server and agent-folder runner
|
|
37896
|
+
*/
|
|
37897
|
+
function createAgentPlannedMessagesSidecarPath(messageFileName) {
|
|
37898
|
+
return path.join(AGENT_PLANNED_MESSAGES_DIRECTORY_PATH, `${createAgentMessageSidecarBaseName(messageFileName)}.json`);
|
|
37899
|
+
}
|
|
37900
|
+
/**
|
|
37901
|
+
* Parses one untrusted planned-message sidecar written back by a coding harness.
|
|
37902
|
+
*
|
|
37903
|
+
* A malformed sidecar never fails the already answered chat, so this returns `null` instead of throwing.
|
|
37904
|
+
*
|
|
37905
|
+
* @param sidecarContent - Raw file content read from the agent folder.
|
|
37906
|
+
* @returns Normalized sidecar, or `null` when it cannot be used.
|
|
37907
|
+
*
|
|
37908
|
+
* @private internal convention shared by the Agents Server and agent-folder runner
|
|
37909
|
+
*/
|
|
37910
|
+
function parseAgentPlannedMessagesSidecar(sidecarContent) {
|
|
37911
|
+
let parsedSidecar;
|
|
37912
|
+
try {
|
|
37913
|
+
parsedSidecar = JSON.parse(sidecarContent);
|
|
37914
|
+
}
|
|
37915
|
+
catch (_a) {
|
|
37916
|
+
return null;
|
|
37917
|
+
}
|
|
37918
|
+
if (!parsedSidecar || typeof parsedSidecar !== 'object' || Array.isArray(parsedSidecar)) {
|
|
37919
|
+
return null;
|
|
37920
|
+
}
|
|
37921
|
+
const sidecar = parsedSidecar;
|
|
37922
|
+
if (sidecar.version !== 1 || typeof sidecar.agentPermanentId !== 'string') {
|
|
37923
|
+
return null;
|
|
37924
|
+
}
|
|
37925
|
+
return {
|
|
37926
|
+
version: 1,
|
|
37927
|
+
agentPermanentId: sidecar.agentPermanentId,
|
|
37928
|
+
currentPlannedMessages: normalizeAgentPlannedMessageSnapshots(sidecar.currentPlannedMessages),
|
|
37929
|
+
commands: normalizeAgentPlannedMessageCommands(sidecar.commands),
|
|
37930
|
+
};
|
|
37931
|
+
}
|
|
37932
|
+
/**
|
|
37933
|
+
* Keeps only the commands whose action is understood by the planned-message actions.
|
|
37934
|
+
*
|
|
37935
|
+
* @param rawCommands - Untrusted `commands` value read from one sidecar.
|
|
37936
|
+
* @returns Commands that can be dispatched, in their original order.
|
|
37937
|
+
*
|
|
37938
|
+
* @private internal utility of `parseAgentPlannedMessagesSidecar`
|
|
37939
|
+
*/
|
|
37940
|
+
function normalizeAgentPlannedMessageCommands(rawCommands) {
|
|
37941
|
+
if (!Array.isArray(rawCommands)) {
|
|
37942
|
+
return [];
|
|
37943
|
+
}
|
|
37944
|
+
return rawCommands.filter(isAgentPlannedMessageCommand);
|
|
37945
|
+
}
|
|
37946
|
+
/**
|
|
37947
|
+
* Checks whether one untrusted sidecar entry names a supported planned-message action.
|
|
37948
|
+
*
|
|
37949
|
+
* @param value - Untrusted command entry.
|
|
37950
|
+
* @returns `true` when the entry can be dispatched.
|
|
37951
|
+
*
|
|
37952
|
+
* @private internal utility of `parseAgentPlannedMessagesSidecar`
|
|
37953
|
+
*/
|
|
37954
|
+
function isAgentPlannedMessageCommand(value) {
|
|
37955
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
37956
|
+
return false;
|
|
37957
|
+
}
|
|
37958
|
+
const action = value.action;
|
|
37959
|
+
return (typeof action === 'string' &&
|
|
37960
|
+
AGENT_PLANNED_MESSAGE_COMMAND_ACTIONS.includes(action));
|
|
37961
|
+
}
|
|
37962
|
+
/**
|
|
37963
|
+
* Keeps only the already planned messages that can be shown to the agent.
|
|
37964
|
+
*
|
|
37965
|
+
* @param rawSnapshots - Untrusted `currentPlannedMessages` value read from one sidecar.
|
|
37966
|
+
* @returns Planned-message snapshots with the fields required for display and cancellation.
|
|
37967
|
+
*
|
|
37968
|
+
* @private internal utility of `parseAgentPlannedMessagesSidecar`
|
|
37969
|
+
*/
|
|
37970
|
+
function normalizeAgentPlannedMessageSnapshots(rawSnapshots) {
|
|
37971
|
+
if (!Array.isArray(rawSnapshots)) {
|
|
37972
|
+
return [];
|
|
37973
|
+
}
|
|
37974
|
+
return rawSnapshots.filter(isAgentPlannedMessageSnapshot).map(createNormalizedAgentPlannedMessageSnapshot);
|
|
37975
|
+
}
|
|
37976
|
+
/**
|
|
37977
|
+
* Normalizes the optional fields of one already planned message.
|
|
37978
|
+
*
|
|
37979
|
+
* @param snapshot - Planned-message entry with the required identity fields.
|
|
37980
|
+
* @returns Snapshot with a usable repeat interval and message.
|
|
37981
|
+
*
|
|
37982
|
+
* @private internal utility of `parseAgentPlannedMessagesSidecar`
|
|
37983
|
+
*/
|
|
37984
|
+
function createNormalizedAgentPlannedMessageSnapshot(snapshot) {
|
|
37985
|
+
const intervalMs = Number(snapshot.intervalMs);
|
|
37986
|
+
return {
|
|
37987
|
+
timeoutId: snapshot.timeoutId,
|
|
37988
|
+
dueAt: snapshot.dueAt,
|
|
37989
|
+
message: typeof snapshot.message === 'string' ? snapshot.message : null,
|
|
37990
|
+
intervalMs: Number.isFinite(intervalMs) && intervalMs > 0 ? Math.floor(intervalMs) : null,
|
|
37991
|
+
};
|
|
37992
|
+
}
|
|
37993
|
+
/**
|
|
37994
|
+
* Checks whether one untrusted sidecar entry describes an already planned message.
|
|
37995
|
+
*
|
|
37996
|
+
* @param value - Untrusted planned-message entry.
|
|
37997
|
+
* @returns `true` when the entry can be shown and cancelled.
|
|
37998
|
+
*
|
|
37999
|
+
* @private internal utility of `parseAgentPlannedMessagesSidecar`
|
|
38000
|
+
*/
|
|
38001
|
+
function isAgentPlannedMessageSnapshot(value) {
|
|
38002
|
+
return Boolean(value &&
|
|
38003
|
+
typeof value === 'object' &&
|
|
38004
|
+
typeof value.timeoutId === 'string' &&
|
|
38005
|
+
typeof value.dueAt === 'string');
|
|
38006
|
+
}
|
|
38007
|
+
|
|
38008
|
+
/**
|
|
38009
|
+
* Loads the planned-message sidecar the Agents Server prepared for one queued message.
|
|
38010
|
+
*
|
|
38011
|
+
* @param projectPath - Absolute path of the current agent runner folder.
|
|
38012
|
+
* @param queuedMessage - Queued message currently being answered.
|
|
38013
|
+
* @returns Sidecar details for the prompt, or `null` outside Agents Server-managed runs.
|
|
38014
|
+
*/
|
|
38015
|
+
async function loadAgentPlannedMessagesSidecar(projectPath, queuedMessage) {
|
|
38016
|
+
const relativeSidecarPath = createAgentPlannedMessagesSidecarPath(queuedMessage.fileName);
|
|
38017
|
+
const sidecarContent = await readOptionalTextFile$2(path.join(projectPath, relativeSidecarPath));
|
|
38018
|
+
if (sidecarContent === null) {
|
|
38019
|
+
return null;
|
|
38020
|
+
}
|
|
38021
|
+
const sidecar = parseAgentPlannedMessagesSidecar(sidecarContent);
|
|
38022
|
+
if (!sidecar) {
|
|
38023
|
+
return null;
|
|
38024
|
+
}
|
|
38025
|
+
return {
|
|
38026
|
+
relativeSidecarPath: toPortablePath$1(relativeSidecarPath),
|
|
38027
|
+
currentPlannedMessages: sidecar.currentPlannedMessages,
|
|
38028
|
+
};
|
|
38029
|
+
}
|
|
38030
|
+
/**
|
|
38031
|
+
* Reads one text file and treats a missing planned-message sidecar as absent.
|
|
38032
|
+
*
|
|
38033
|
+
* @param path - Absolute sidecar path.
|
|
38034
|
+
* @returns File content, or `null` when the sidecar does not exist.
|
|
38035
|
+
*/
|
|
38036
|
+
async function readOptionalTextFile$2(path) {
|
|
38037
|
+
try {
|
|
38038
|
+
return await promises.readFile(path, 'utf-8');
|
|
38039
|
+
}
|
|
38040
|
+
catch (error) {
|
|
38041
|
+
if (isFileNotFoundError$2(error)) {
|
|
38042
|
+
return null;
|
|
38043
|
+
}
|
|
38044
|
+
throw error;
|
|
38045
|
+
}
|
|
38046
|
+
}
|
|
38047
|
+
/**
|
|
38048
|
+
* Converts a filesystem-relative path to the portable form used in prompts.
|
|
38049
|
+
*
|
|
38050
|
+
* @param path - Relative path inside the agent folder.
|
|
38051
|
+
* @returns Path with forward slashes.
|
|
38052
|
+
*/
|
|
37521
38053
|
function toPortablePath$1(path) {
|
|
37522
38054
|
return path.replace(/\\/gu, '/');
|
|
37523
38055
|
}
|
|
37524
38056
|
/**
|
|
37525
38057
|
* Returns true when one filesystem error indicates a missing path.
|
|
38058
|
+
*
|
|
38059
|
+
* @param error - Caught filesystem failure.
|
|
38060
|
+
* @returns `true` for missing-path errors.
|
|
37526
38061
|
*/
|
|
37527
38062
|
function isFileNotFoundError$2(error) {
|
|
37528
38063
|
return Boolean(error &&
|
|
@@ -37537,7 +38072,7 @@
|
|
|
37537
38072
|
async function loadAgentTeamConversationWorkspace(projectPath, queuedMessage) {
|
|
37538
38073
|
const relativeWorkspacePath = createAgentTeamConversationWorkspacePath(queuedMessage.fileName);
|
|
37539
38074
|
const manifestPath = path.join(projectPath, relativeWorkspacePath, AGENT_TEAM_CONVERSATION_MANIFEST_FILE_NAME);
|
|
37540
|
-
const manifestContent = await readOptionalTextFile(manifestPath);
|
|
38075
|
+
const manifestContent = await readOptionalTextFile$1(manifestPath);
|
|
37541
38076
|
if (manifestContent === null) {
|
|
37542
38077
|
return null;
|
|
37543
38078
|
}
|
|
@@ -37565,7 +38100,7 @@
|
|
|
37565
38100
|
/**
|
|
37566
38101
|
* Reads one text file and treats a missing team workspace as absent.
|
|
37567
38102
|
*/
|
|
37568
|
-
async function readOptionalTextFile(path) {
|
|
38103
|
+
async function readOptionalTextFile$1(path) {
|
|
37569
38104
|
try {
|
|
37570
38105
|
return await promises.readFile(path, 'utf-8');
|
|
37571
38106
|
}
|
|
@@ -37632,6 +38167,233 @@
|
|
|
37632
38167
|
return `/agents/${encodeURIComponent(agentId)}/projects`;
|
|
37633
38168
|
}
|
|
37634
38169
|
|
|
38170
|
+
/**
|
|
38171
|
+
* Parses every structured event out of one coding-harness runtime log.
|
|
38172
|
+
*
|
|
38173
|
+
* The local agent runner streams the answering harness output into a live runtime log file, one
|
|
38174
|
+
* JSON event per line, optionally prefixed by shell noise. Lines without a usable JSON object are
|
|
38175
|
+
* skipped so a partially written or interleaved log never breaks its consumers.
|
|
38176
|
+
*
|
|
38177
|
+
* @param logText - Raw runtime log content.
|
|
38178
|
+
* @returns Structured events in the order they were streamed.
|
|
38179
|
+
* @private internal utility of the agent-message runtime
|
|
38180
|
+
*/
|
|
38181
|
+
function parseAgentMessageRuntimeLogEvents(logText) {
|
|
38182
|
+
if (!logText) {
|
|
38183
|
+
return [];
|
|
38184
|
+
}
|
|
38185
|
+
const events = [];
|
|
38186
|
+
for (const line of logText.split(/\r?\n/u)) {
|
|
38187
|
+
const event = parseAgentMessageRuntimeLogEvent(line);
|
|
38188
|
+
if (event) {
|
|
38189
|
+
events.push(event);
|
|
38190
|
+
}
|
|
38191
|
+
}
|
|
38192
|
+
return events;
|
|
38193
|
+
}
|
|
38194
|
+
/**
|
|
38195
|
+
* Parses one runtime log line into a structured event when it embeds JSON.
|
|
38196
|
+
*
|
|
38197
|
+
* @param line - One raw runtime log line.
|
|
38198
|
+
* @returns Structured event, or `null` when the line carries no JSON object.
|
|
38199
|
+
* @private internal helper of `parseAgentMessageRuntimeLogEvents`
|
|
38200
|
+
*/
|
|
38201
|
+
function parseAgentMessageRuntimeLogEvent(line) {
|
|
38202
|
+
const jsonStartIndex = line.indexOf('{');
|
|
38203
|
+
if (jsonStartIndex === -1) {
|
|
38204
|
+
return null;
|
|
38205
|
+
}
|
|
38206
|
+
try {
|
|
38207
|
+
const parsedEvent = JSON.parse(line.slice(jsonStartIndex).trim());
|
|
38208
|
+
if (typeof parsedEvent !== 'object' || parsedEvent === null || Array.isArray(parsedEvent)) {
|
|
38209
|
+
return null;
|
|
38210
|
+
}
|
|
38211
|
+
return parsedEvent;
|
|
38212
|
+
}
|
|
38213
|
+
catch (_a) {
|
|
38214
|
+
return null;
|
|
38215
|
+
}
|
|
38216
|
+
}
|
|
38217
|
+
|
|
38218
|
+
/**
|
|
38219
|
+
* Matches one project directory name following the agent `projects/` folder in a file path or command.
|
|
38220
|
+
*
|
|
38221
|
+
* Both path separators are accepted because the local runner answers messages on Unix and Windows,
|
|
38222
|
+
* and JSON-encoded payloads escape backslashes.
|
|
38223
|
+
*
|
|
38224
|
+
* @private internal constant of agent-message touched projects
|
|
38225
|
+
*/
|
|
38226
|
+
const TOUCHED_PROJECT_PATH_REGEX = new RegExp(`${AGENT_PROJECTS_DIRECTORY_PATH}[\\\\/]+([^\\\\/"'\\s,;:]+)`, 'giu');
|
|
38227
|
+
/**
|
|
38228
|
+
* Resolves which projects one coding harness touched while answering a single message.
|
|
38229
|
+
*
|
|
38230
|
+
* The runtime log streams what the harness really did, so a project counts as touched when the
|
|
38231
|
+
* harness named it in a tool invocation — reading, searching, running, or editing files inside
|
|
38232
|
+
* `projects/<project-name>/`. Only tool payloads are inspected: tool results and assistant
|
|
38233
|
+
* narration are ignored so a project merely mentioned in the conversation is never reported.
|
|
38234
|
+
*
|
|
38235
|
+
* Every candidate is matched against the projects that really exist, which both filters prompt
|
|
38236
|
+
* placeholders such as `projects/<project-name>/` and keeps the reported names canonical.
|
|
38237
|
+
*
|
|
38238
|
+
* @param options - Raw runtime log content and the project directory names of the agent.
|
|
38239
|
+
* @returns Touched project names in the canonical spelling, ordered by first appearance.
|
|
38240
|
+
* @private internal utility of the agent-message runtime
|
|
38241
|
+
*/
|
|
38242
|
+
function resolveAgentMessageTouchedProjectNames(options) {
|
|
38243
|
+
const canonicalProjectNames = createCanonicalProjectNameLookup(options.knownProjectNames);
|
|
38244
|
+
if (canonicalProjectNames.size === 0) {
|
|
38245
|
+
return [];
|
|
38246
|
+
}
|
|
38247
|
+
const touchedProjectNames = new Set();
|
|
38248
|
+
for (const event of parseAgentMessageRuntimeLogEvents(options.logText)) {
|
|
38249
|
+
for (const toolInvocationText of resolveRuntimeLogEventToolInvocationTexts(event)) {
|
|
38250
|
+
for (const candidateProjectName of resolveCandidateProjectNames(toolInvocationText)) {
|
|
38251
|
+
const canonicalProjectName = canonicalProjectNames.get(candidateProjectName.toLowerCase());
|
|
38252
|
+
if (canonicalProjectName !== undefined) {
|
|
38253
|
+
touchedProjectNames.add(canonicalProjectName);
|
|
38254
|
+
}
|
|
38255
|
+
}
|
|
38256
|
+
}
|
|
38257
|
+
}
|
|
38258
|
+
return Array.from(touchedProjectNames);
|
|
38259
|
+
}
|
|
38260
|
+
/**
|
|
38261
|
+
* Indexes the existing project directory names by their lower-cased form.
|
|
38262
|
+
*
|
|
38263
|
+
* @param knownProjectNames - Project directory names of the agent.
|
|
38264
|
+
* @returns Lookup from the lower-cased name to its canonical spelling.
|
|
38265
|
+
* @private internal helper of `resolveAgentMessageTouchedProjectNames`
|
|
38266
|
+
*/
|
|
38267
|
+
function createCanonicalProjectNameLookup(knownProjectNames) {
|
|
38268
|
+
const canonicalProjectNames = new Map();
|
|
38269
|
+
for (const knownProjectName of knownProjectNames) {
|
|
38270
|
+
const normalizedProjectName = knownProjectName.trim();
|
|
38271
|
+
if (normalizedProjectName.length > 0) {
|
|
38272
|
+
canonicalProjectNames.set(normalizedProjectName.toLowerCase(), normalizedProjectName);
|
|
38273
|
+
}
|
|
38274
|
+
}
|
|
38275
|
+
return canonicalProjectNames;
|
|
38276
|
+
}
|
|
38277
|
+
/**
|
|
38278
|
+
* Collects the texts of every tool invocation described by one runtime log event.
|
|
38279
|
+
*
|
|
38280
|
+
* Claude Code reports tool invocations as `tool_use` content blocks, while Codex reports executed
|
|
38281
|
+
* commands and file changes as items — both carry the paths the harness worked with.
|
|
38282
|
+
*
|
|
38283
|
+
* @param event - One structured runtime log event.
|
|
38284
|
+
* @returns Texts that may contain project paths.
|
|
38285
|
+
* @private internal helper of `resolveAgentMessageTouchedProjectNames`
|
|
38286
|
+
*/
|
|
38287
|
+
function resolveRuntimeLogEventToolInvocationTexts(event) {
|
|
38288
|
+
var _a, _b, _c;
|
|
38289
|
+
const toolInvocationTexts = [];
|
|
38290
|
+
for (const contentBlock of ((_a = event.message) === null || _a === void 0 ? void 0 : _a.content) || []) {
|
|
38291
|
+
if (contentBlock.type === 'tool_use' && contentBlock.input) {
|
|
38292
|
+
toolInvocationTexts.push(serializeToolInput(contentBlock.input));
|
|
38293
|
+
}
|
|
38294
|
+
}
|
|
38295
|
+
if (typeof ((_b = event.item) === null || _b === void 0 ? void 0 : _b.command) === 'string') {
|
|
38296
|
+
toolInvocationTexts.push(event.item.command);
|
|
38297
|
+
}
|
|
38298
|
+
for (const fileChange of ((_c = event.item) === null || _c === void 0 ? void 0 : _c.changes) || []) {
|
|
38299
|
+
if (typeof fileChange.path === 'string') {
|
|
38300
|
+
toolInvocationTexts.push(fileChange.path);
|
|
38301
|
+
}
|
|
38302
|
+
}
|
|
38303
|
+
return toolInvocationTexts;
|
|
38304
|
+
}
|
|
38305
|
+
/**
|
|
38306
|
+
* Serializes one tool input payload into scannable text.
|
|
38307
|
+
*
|
|
38308
|
+
* @param toolInput - Tool arguments of one harness tool invocation.
|
|
38309
|
+
* @returns Serialized payload, or an empty string when it cannot be serialized.
|
|
38310
|
+
* @private internal helper of `resolveAgentMessageTouchedProjectNames`
|
|
38311
|
+
*/
|
|
38312
|
+
function serializeToolInput(toolInput) {
|
|
38313
|
+
try {
|
|
38314
|
+
return JSON.stringify(toolInput);
|
|
38315
|
+
}
|
|
38316
|
+
catch (_a) {
|
|
38317
|
+
return '';
|
|
38318
|
+
}
|
|
38319
|
+
}
|
|
38320
|
+
/**
|
|
38321
|
+
* Extracts every project directory name mentioned right after the agent `projects/` folder.
|
|
38322
|
+
*
|
|
38323
|
+
* @param toolInvocationText - One tool payload, command, or changed path.
|
|
38324
|
+
* @returns Candidate project directory names.
|
|
38325
|
+
* @private internal helper of `resolveAgentMessageTouchedProjectNames`
|
|
38326
|
+
*/
|
|
38327
|
+
function resolveCandidateProjectNames(toolInvocationText) {
|
|
38328
|
+
const candidateProjectNames = [];
|
|
38329
|
+
const projectPathRegex = new RegExp(TOUCHED_PROJECT_PATH_REGEX.source, TOUCHED_PROJECT_PATH_REGEX.flags);
|
|
38330
|
+
let projectPathMatch = projectPathRegex.exec(toolInvocationText);
|
|
38331
|
+
while (projectPathMatch !== null) {
|
|
38332
|
+
const candidateProjectName = projectPathMatch[1];
|
|
38333
|
+
if (candidateProjectName) {
|
|
38334
|
+
candidateProjectNames.push(candidateProjectName);
|
|
38335
|
+
}
|
|
38336
|
+
projectPathMatch = projectPathRegex.exec(toolInvocationText);
|
|
38337
|
+
}
|
|
38338
|
+
return candidateProjectNames;
|
|
38339
|
+
}
|
|
38340
|
+
|
|
38341
|
+
/**
|
|
38342
|
+
* Resolves which agent projects one answered message viewed or edited.
|
|
38343
|
+
*
|
|
38344
|
+
* The runtime log is deleted as soon as the harness run finishes, so this must be called while
|
|
38345
|
+
* the log still exists — the Agents Server later shows the reported projects as chips below the
|
|
38346
|
+
* answer. Reporting touched projects is best-effort telemetry: an unreadable log or projects
|
|
38347
|
+
* folder simply yields no projects instead of failing the already answered message.
|
|
38348
|
+
*
|
|
38349
|
+
* @param options - Agent folder path and the live runtime log path of the answered message.
|
|
38350
|
+
* @returns Touched project directory names, ordered by first appearance in the run.
|
|
38351
|
+
*/
|
|
38352
|
+
async function resolveTouchedAgentProjects(options) {
|
|
38353
|
+
const [logText, knownProjectNames] = await Promise.all([
|
|
38354
|
+
readOptionalTextFile(options.runtimeLogPath),
|
|
38355
|
+
listAgentProjectDirectoryNames(options.projectPath),
|
|
38356
|
+
]);
|
|
38357
|
+
return resolveAgentMessageTouchedProjectNames({ logText, knownProjectNames });
|
|
38358
|
+
}
|
|
38359
|
+
/**
|
|
38360
|
+
* Lists the direct project directories of one agent folder.
|
|
38361
|
+
*
|
|
38362
|
+
* @param projectPath - Absolute path of the local agent folder.
|
|
38363
|
+
* @returns Project directory names, or an empty list when the agent has no projects folder.
|
|
38364
|
+
*
|
|
38365
|
+
* @private helper of `resolveTouchedAgentProjects`
|
|
38366
|
+
*/
|
|
38367
|
+
async function listAgentProjectDirectoryNames(projectPath) {
|
|
38368
|
+
try {
|
|
38369
|
+
const projectsRootEntries = await promises.readdir(path.join(projectPath, AGENT_PROJECTS_DIRECTORY_PATH), {
|
|
38370
|
+
withFileTypes: true,
|
|
38371
|
+
});
|
|
38372
|
+
return projectsRootEntries
|
|
38373
|
+
.filter((projectsRootEntry) => projectsRootEntry.isDirectory())
|
|
38374
|
+
.map((projectDirectoryEntry) => projectDirectoryEntry.name);
|
|
38375
|
+
}
|
|
38376
|
+
catch (_a) {
|
|
38377
|
+
return [];
|
|
38378
|
+
}
|
|
38379
|
+
}
|
|
38380
|
+
/**
|
|
38381
|
+
* Reads one text file and treats a missing runtime log as "nothing was recorded".
|
|
38382
|
+
*
|
|
38383
|
+
* @param filePath - Absolute path of the file to read.
|
|
38384
|
+
* @returns File content, or `null` when it cannot be read.
|
|
38385
|
+
*
|
|
38386
|
+
* @private helper of `resolveTouchedAgentProjects`
|
|
38387
|
+
*/
|
|
38388
|
+
async function readOptionalTextFile(filePath) {
|
|
38389
|
+
try {
|
|
38390
|
+
return await promises.readFile(filePath, 'utf-8');
|
|
38391
|
+
}
|
|
38392
|
+
catch (_a) {
|
|
38393
|
+
return null;
|
|
38394
|
+
}
|
|
38395
|
+
}
|
|
38396
|
+
|
|
37635
38397
|
// Note: [💞] Ignore a discrepancy between file name and entity name
|
|
37636
38398
|
/**
|
|
37637
38399
|
* File suffix appended to one answered message book to store its run report sidecar.
|
|
@@ -37911,10 +38673,11 @@
|
|
|
37911
38673
|
const { projectPath, options: runOptions, runner, actualRunnerModel, queuedMessage, uiHandle, isSharedDashboard, } = options;
|
|
37912
38674
|
const agentSystemMessage = await loadLocalAgentSystemMessage(projectPath);
|
|
37913
38675
|
const teamWorkspace = await loadAgentTeamConversationWorkspace(projectPath, queuedMessage);
|
|
38676
|
+
const plannedMessagesSidecar = await loadAgentPlannedMessagesSidecar(projectPath, queuedMessage);
|
|
37914
38677
|
const agentServerRuntimeApi = resolveAgentProjectRuntimePromptApi(projectPath);
|
|
37915
38678
|
const prompt = buildAgentMessagePrompt(queuedMessage.relativePath, agentSystemMessage, {
|
|
37916
38679
|
projectRuntimeApi: agentServerRuntimeApi,
|
|
37917
|
-
|
|
38680
|
+
plannedMessagesSidecar: plannedMessagesSidecar || undefined,
|
|
37918
38681
|
projectsUrlPath: resolveAgentProjectsUrlPath(projectPath),
|
|
37919
38682
|
teamWorkspace: teamWorkspace || undefined,
|
|
37920
38683
|
});
|
|
@@ -37935,21 +38698,29 @@
|
|
|
37935
38698
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setCurrentScriptPath(scriptPath);
|
|
37936
38699
|
}
|
|
37937
38700
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
38701
|
+
const executionStartedAt = new Date().toISOString();
|
|
37938
38702
|
let promptRunResult;
|
|
38703
|
+
let touchedProjectNames = [];
|
|
37939
38704
|
try {
|
|
37940
38705
|
try {
|
|
37941
|
-
promptRunResult = await withPromptRuntimeLog(scriptPath, async (logPath) =>
|
|
37942
|
-
|
|
37943
|
-
|
|
37944
|
-
|
|
37945
|
-
|
|
37946
|
-
|
|
37947
|
-
|
|
37948
|
-
|
|
37949
|
-
|
|
37950
|
-
|
|
37951
|
-
|
|
37952
|
-
|
|
38706
|
+
promptRunResult = await withPromptRuntimeLog(scriptPath, async (logPath) => {
|
|
38707
|
+
const runResult = await runPromptWithTestFeedback({
|
|
38708
|
+
runner,
|
|
38709
|
+
prompt,
|
|
38710
|
+
scriptPath,
|
|
38711
|
+
projectPath,
|
|
38712
|
+
promptLabel: queuedMessage.relativePath,
|
|
38713
|
+
logPath,
|
|
38714
|
+
preserveArtifactsOnSuccess: false,
|
|
38715
|
+
onAttemptStarted: (attemptCount) => {
|
|
38716
|
+
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.state.setAttempt(attemptCount);
|
|
38717
|
+
},
|
|
38718
|
+
});
|
|
38719
|
+
// Note: The runtime log is deleted right after this handler, so the projects this
|
|
38720
|
+
// answer worked with must be resolved while the log still exists.
|
|
38721
|
+
touchedProjectNames = await resolveTouchedAgentProjects({ projectPath, runtimeLogPath: logPath });
|
|
38722
|
+
return runResult;
|
|
38723
|
+
}, { preserveArtifactsOnSuccess: false });
|
|
37953
38724
|
}
|
|
37954
38725
|
catch (error) {
|
|
37955
38726
|
throw withAgentWatchErrorContext(error, {
|
|
@@ -37963,6 +38734,7 @@
|
|
|
37963
38734
|
finally {
|
|
37964
38735
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
37965
38736
|
}
|
|
38737
|
+
const executionFinishedAt = new Date().toISOString();
|
|
37966
38738
|
await normalizeLineEndingsForAgentRound(projectPath, runOptions, roundChangedFilesSnapshot);
|
|
37967
38739
|
const finishedTeamWorkspace = await finalizeAgentTeamConversationWorkspace({
|
|
37968
38740
|
projectPath,
|
|
@@ -37981,6 +38753,11 @@
|
|
|
37981
38753
|
modelName: actualRunnerModel,
|
|
37982
38754
|
loginMethod: promptRunResult.loginMethod,
|
|
37983
38755
|
usage: promptRunResult.usage,
|
|
38756
|
+
executionTiming: {
|
|
38757
|
+
startedAt: executionStartedAt,
|
|
38758
|
+
finishedAt: executionFinishedAt,
|
|
38759
|
+
},
|
|
38760
|
+
...(touchedProjectNames.length === 0 ? {} : { touchedProjectNames }),
|
|
37984
38761
|
},
|
|
37985
38762
|
});
|
|
37986
38763
|
await commitAnsweredMessageIfEnabled({
|
|
@@ -39673,24 +40450,12 @@
|
|
|
39673
40450
|
- @@@
|
|
39674
40451
|
- Keep in mind the DRY _(don't repeat yourself)_ principle.
|
|
39675
40452
|
- Do a proper analysis of the current functionality before you start implementing.
|
|
39676
|
-
- Add the changes into the [changelog](
|
|
40453
|
+
- Add the changes into the [changelog](CHANGELOG.md)
|
|
40454
|
+
- Update the [README](README.md) if needed.
|
|
40455
|
+
- Update the [AGENTS.md](AGENTS.md) for the next job to be done if it makes sense.
|
|
39677
40456
|
`),
|
|
39678
40457
|
isDefaultProjectTemplate: true,
|
|
39679
40458
|
},
|
|
39680
|
-
{
|
|
39681
|
-
id: 'agents-server',
|
|
39682
|
-
relativeFilePath: path.join(PROMPTS_TEMPLATES_DIRECTORY_PATH, 'agents-server.md'),
|
|
39683
|
-
slugPrefix: 'agents-server',
|
|
39684
|
-
content: _spaceTrim.spaceTrim(`
|
|
39685
|
-
- @@@
|
|
39686
|
-
- Keep in mind the DRY _(don't repeat yourself)_ principle.
|
|
39687
|
-
- Do a proper analysis of the current functionality before you start implementing.
|
|
39688
|
-
- You are working with the [Agents Server](apps/agents-server)
|
|
39689
|
-
- If you need to do the database migration, do it
|
|
39690
|
-
- Add the changes into the [changelog](changelog/_current-preversion.md)
|
|
39691
|
-
`),
|
|
39692
|
-
isDefaultProjectTemplate: false,
|
|
39693
|
-
},
|
|
39694
40459
|
];
|
|
39695
40460
|
/**
|
|
39696
40461
|
* Project-agnostic coder templates that `ptbk coder init` should materialize in any repository.
|
|
@@ -40782,6 +41547,10 @@
|
|
|
40782
41547
|
console.info(colors__default["default"].gray(`✔ ${definition.label} ${installedVersion} is up to date.`));
|
|
40783
41548
|
return;
|
|
40784
41549
|
}
|
|
41550
|
+
if (installationState === 'installed') {
|
|
41551
|
+
console.info(colors__default["default"].gray(`✔ ${definition.label} ${installedVersion} is installed. Skipped checking for updates.`));
|
|
41552
|
+
return;
|
|
41553
|
+
}
|
|
40785
41554
|
if (installationState === 'unknown') {
|
|
40786
41555
|
console.info(colors__default["default"].gray(`✔ ${definition.label} ${installedVersion} is installed, the newest version could not be checked.`));
|
|
40787
41556
|
return;
|
|
@@ -40995,20 +41764,20 @@
|
|
|
40995
41764
|
// Note: [🟡] Code for CLI npm package version comparison [isNpmPackageVersionOutdated](src/cli/cli-commands/common/npm/isNpmPackageVersionOutdated.ts) should never be published outside of `@promptbook/cli`
|
|
40996
41765
|
|
|
40997
41766
|
/**
|
|
40998
|
-
* Detects whether one CLI coding harness is installed globally and whether it is up to date.
|
|
41767
|
+
* Detects whether one CLI coding harness is installed globally and, when enabled, whether it is up to date.
|
|
40999
41768
|
*
|
|
41000
|
-
* Note: `$` is used to indicate that this function is not a pure function - it runs the harness command and
|
|
41769
|
+
* Note: `$` is used to indicate that this function is not a pure function - it runs the harness command and may query npm
|
|
41001
41770
|
*
|
|
41002
41771
|
* @private internal utility of `promptbookCli`
|
|
41003
41772
|
*/
|
|
41004
|
-
async function $checkHarnessInstallation(definition) {
|
|
41773
|
+
async function $checkHarnessInstallation(definition, isHarnessUpdateCheckEnabled = true) {
|
|
41005
41774
|
const [installedVersion, latestVersion] = await Promise.all([
|
|
41006
41775
|
$resolveInstalledHarnessVersion(definition),
|
|
41007
|
-
$resolveLatestNpmPackageVersion(definition.npmPackageName),
|
|
41776
|
+
isHarnessUpdateCheckEnabled ? $resolveLatestNpmPackageVersion(definition.npmPackageName) : Promise.resolve(null),
|
|
41008
41777
|
]);
|
|
41009
41778
|
return {
|
|
41010
41779
|
definition,
|
|
41011
|
-
installationState: resolveHarnessInstallationState(installedVersion, latestVersion),
|
|
41780
|
+
installationState: resolveHarnessInstallationState(installedVersion, latestVersion, isHarnessUpdateCheckEnabled),
|
|
41012
41781
|
installedVersion,
|
|
41013
41782
|
latestVersion,
|
|
41014
41783
|
};
|
|
@@ -41016,10 +41785,13 @@
|
|
|
41016
41785
|
/**
|
|
41017
41786
|
* Derives the installation state from the detected versions.
|
|
41018
41787
|
*/
|
|
41019
|
-
function resolveHarnessInstallationState(installedVersion, latestVersion) {
|
|
41788
|
+
function resolveHarnessInstallationState(installedVersion, latestVersion, isHarnessUpdateCheckEnabled) {
|
|
41020
41789
|
if (installedVersion === null) {
|
|
41021
41790
|
return 'not-installed';
|
|
41022
41791
|
}
|
|
41792
|
+
if (!isHarnessUpdateCheckEnabled) {
|
|
41793
|
+
return 'installed';
|
|
41794
|
+
}
|
|
41023
41795
|
if (latestVersion === null) {
|
|
41024
41796
|
return 'unknown';
|
|
41025
41797
|
}
|
|
@@ -41030,8 +41802,8 @@
|
|
|
41030
41802
|
// Note: [🟡] Code for CLI harness installation check [$checkHarnessInstallation](src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts) should never be published outside of `@promptbook/cli`
|
|
41031
41803
|
|
|
41032
41804
|
/**
|
|
41033
|
-
* Checks that every given CLI coding harness is installed globally and up to date
|
|
41034
|
-
* install
|
|
41805
|
+
* Checks that every given CLI coding harness is installed globally and, when enabled, up to date.
|
|
41806
|
+
* Offers to install missing harnesses and update outdated ones.
|
|
41035
41807
|
*
|
|
41036
41808
|
* Harness names which are `undefined`, for example when no `--harness` is selected in a dry run,
|
|
41037
41809
|
* are ignored so that every call site can pass its raw selection.
|
|
@@ -41040,13 +41812,13 @@
|
|
|
41040
41812
|
*
|
|
41041
41813
|
* @private internal utility of `promptbookCli`
|
|
41042
41814
|
*/
|
|
41043
|
-
async function $ensureHarnessInstallations(harnessNames) {
|
|
41815
|
+
async function $ensureHarnessInstallations(harnessNames, isHarnessUpdateCheckEnabled = true) {
|
|
41044
41816
|
const definitions = resolveCheckedHarnessDefinitions(harnessNames);
|
|
41045
41817
|
if (definitions.length === 0) {
|
|
41046
41818
|
return;
|
|
41047
41819
|
}
|
|
41048
41820
|
// Note: Detection of all harnesses runs in parallel, the questions have to be asked one by one
|
|
41049
|
-
const statuses = await Promise.all(definitions.map((definition) => $checkHarnessInstallation(definition)));
|
|
41821
|
+
const statuses = await Promise.all(definitions.map((definition) => $checkHarnessInstallation(definition, isHarnessUpdateCheckEnabled)));
|
|
41050
41822
|
for (const status of statuses) {
|
|
41051
41823
|
await $applyHarnessInstallationStatus(status);
|
|
41052
41824
|
}
|
|
@@ -41060,6 +41832,27 @@
|
|
|
41060
41832
|
}
|
|
41061
41833
|
// Note: [🟡] Code for CLI harness installation orchestration [$ensureHarnessInstallations](src/cli/cli-commands/common/harness/$ensureHarnessInstallations.ts) should never be published outside of `@promptbook/cli`
|
|
41062
41834
|
|
|
41835
|
+
/**
|
|
41836
|
+
* Registers the shared `--no-harness-update` option on a `ptbk coder` command that uses a coding harness.
|
|
41837
|
+
*
|
|
41838
|
+
* @private internal utility of `promptbookCli`
|
|
41839
|
+
*/
|
|
41840
|
+
function addHarnessUpdateOption(command) {
|
|
41841
|
+
command.option('--no-harness-update', 'Skip checking whether globally installed coding harnesses are up to date');
|
|
41842
|
+
}
|
|
41843
|
+
/**
|
|
41844
|
+
* Converts the Commander harness-update flag into the normalized harness-check option.
|
|
41845
|
+
*
|
|
41846
|
+
* @private internal utility of `promptbookCli`
|
|
41847
|
+
*/
|
|
41848
|
+
function normalizeHarnessUpdateCliOptions(cliOptions) {
|
|
41849
|
+
return {
|
|
41850
|
+
isHarnessUpdateCheckEnabled: cliOptions.harnessUpdate,
|
|
41851
|
+
};
|
|
41852
|
+
}
|
|
41853
|
+
// Note: [🟡] Code for CLI harness update options [harnessUpdateCliOptions](src/cli/cli-commands/common/harnessUpdateCliOptions.ts) should never be published outside of `@promptbook/cli`
|
|
41854
|
+
// Note: [💞] Ignore a discrepancy between file name and exported helper names
|
|
41855
|
+
|
|
41063
41856
|
/**
|
|
41064
41857
|
* Relative path to the Promptbook Coder quick-reference file initialized in project roots.
|
|
41065
41858
|
*
|
|
@@ -41622,14 +42415,16 @@
|
|
|
41622
42415
|
- CODING_AGENT_GIT_EMAIL
|
|
41623
42416
|
- CODING_AGENT_GIT_SIGNING_KEY
|
|
41624
42417
|
|
|
41625
|
-
Checks that the coding harnesses are installed globally and up to date:
|
|
42418
|
+
Checks that the coding harnesses are installed globally and up to date unless \`--no-harness-update\` is used:
|
|
41626
42419
|
${block(listCheckedHarnessLabels())}
|
|
41627
42420
|
|
|
41628
42421
|
${block(CODER_GIT_SYNC_DESCRIPTION)}
|
|
41629
42422
|
`));
|
|
41630
42423
|
addCoderGitSyncOptions(command);
|
|
42424
|
+
addHarnessUpdateOption(command);
|
|
41631
42425
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
41632
42426
|
const gitSync = normalizeCoderGitSyncCliOptions(cliOptions);
|
|
42427
|
+
const { isHarnessUpdateCheckEnabled } = normalizeHarnessUpdateCliOptions(cliOptions);
|
|
41633
42428
|
const projectPath = process.cwd();
|
|
41634
42429
|
// Note: Import the git synchronization dynamically to keep the CLI fast for runs without `--commit`
|
|
41635
42430
|
const { $commitCoderChanges, $startCoderGitSync } = await Promise.resolve().then(function () { return coderGitSync; });
|
|
@@ -41642,7 +42437,7 @@
|
|
|
41642
42437
|
commitScope,
|
|
41643
42438
|
commitMessage: 'Initialize Promptbook Coder',
|
|
41644
42439
|
});
|
|
41645
|
-
await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES);
|
|
42440
|
+
await $ensureHarnessInstallations(CODER_INIT_CHECKED_HARNESS_NAMES, isHarnessUpdateCheckEnabled);
|
|
41646
42441
|
}));
|
|
41647
42442
|
}
|
|
41648
42443
|
/**
|
|
@@ -41681,13 +42476,16 @@
|
|
|
41681
42476
|
- Reports the answer of the harness, the response time and the reported usage
|
|
41682
42477
|
- Starts the hourly/weekly quota window before you need it, so it is already refreshing when you do
|
|
41683
42478
|
- Leaves the project exactly as it was — nothing is read, written, changed or committed
|
|
42479
|
+
- Checks that the selected harness is installed globally and up to date unless --no-harness-update is used
|
|
41684
42480
|
- Use --no-ui to stream the raw harness output instead of only the compact result
|
|
41685
42481
|
`));
|
|
41686
42482
|
addPromptRunnerSelectionOptions(command);
|
|
42483
|
+
addHarnessUpdateOption(command);
|
|
41687
42484
|
addPromptRunnerRuntimeOptions(command);
|
|
41688
42485
|
command.action(handleActionErrors(async (cliOptions) => {
|
|
41689
42486
|
const runnerOptions = normalizePromptRunnerSelectionCliOptions(cliOptions, { isAgentRequired: true });
|
|
41690
|
-
|
|
42487
|
+
const { isHarnessUpdateCheckEnabled } = normalizeHarnessUpdateCliOptions(cliOptions);
|
|
42488
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
41691
42489
|
// Note: Import the ping dynamically to avoid loading heavy dependencies until needed
|
|
41692
42490
|
const { pingCoderHarness } = await Promise.resolve().then(function () { return pingCoderHarness$1; });
|
|
41693
42491
|
const { printCoderPingResult } = await Promise.resolve().then(function () { return printCoderPingResult$1; });
|
|
@@ -42178,7 +42976,7 @@
|
|
|
42178
42976
|
- Optional --isolate runs every prompt in its own temporary git worktree and merges it back when verified
|
|
42179
42977
|
- Optional --preserve-logs keeps temp prompt/log artifacts after successful rounds
|
|
42180
42978
|
- Optional --no-ui keeps plain streaming console output for logging and debugging
|
|
42181
|
-
- Checks that the selected harness is installed globally and up to date before the first prompt
|
|
42979
|
+
- Checks that the selected harness is installed globally and up to date before the first prompt unless --no-harness-update is used
|
|
42182
42980
|
- In interactive mode, checks local and global Promptbook CLI installations and offers to update them
|
|
42183
42981
|
- Supports GPG signing of commits
|
|
42184
42982
|
- Optional pre-coding test run that can stop or repair pre-existing failures
|
|
@@ -42188,6 +42986,7 @@
|
|
|
42188
42986
|
`));
|
|
42189
42987
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
42190
42988
|
addPromptRunnerSelectionOptions(command);
|
|
42989
|
+
addHarnessUpdateOption(command);
|
|
42191
42990
|
command.option('--agent <agent-book-path>', 'Path to a .book file whose compiled system message is prepended to each coding prompt');
|
|
42192
42991
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
42193
42992
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
@@ -42229,6 +43028,7 @@
|
|
|
42229
43028
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
42230
43029
|
isAgentRequired: !dryRun,
|
|
42231
43030
|
});
|
|
43031
|
+
const { isHarnessUpdateCheckEnabled } = normalizeHarnessUpdateCliOptions(cliOptions);
|
|
42232
43032
|
// [1] Parse the wait options and --no-auto:
|
|
42233
43033
|
// default: run automatically through the queue (no waiting between prompts)
|
|
42234
43034
|
// --no-auto: wait for user confirmation before each prompt (interactive mode)
|
|
@@ -42239,7 +43039,7 @@
|
|
|
42239
43039
|
if (await $ensurePromptbookCliInstallations()) {
|
|
42240
43040
|
return process.exit(0);
|
|
42241
43041
|
}
|
|
42242
|
-
await $ensureHarnessInstallations([runnerOptions.agentName]);
|
|
43042
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
42243
43043
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
42244
43044
|
const waitBetweenPrompts = parseOptionalWaitDuration(waitBetweenPromptsValue, 0);
|
|
42245
43045
|
const waitAfterError = parseOptionalWaitDuration(waitAfterErrorValue, DEFAULT_WAIT_AFTER_ERROR_MS$1);
|
|
@@ -42333,7 +43133,7 @@
|
|
|
42333
43133
|
|
|
42334
43134
|
Features:
|
|
42335
43135
|
- Runs the same prompt processing as \`ptbk coder run\`
|
|
42336
|
-
- Checks that the selected harness is installed globally and up to date on startup
|
|
43136
|
+
- Checks that the selected harness is installed globally and up to date on startup unless --no-harness-update is used
|
|
42337
43137
|
- Does not exit when all prompts are done; polls for new prompt files instead
|
|
42338
43138
|
- Serves a kanban board at http://localhost:<port> for visual progress tracking
|
|
42339
43139
|
- Allows editing prompt files directly from the browser (Trello-style)
|
|
@@ -42345,6 +43145,7 @@
|
|
|
42345
43145
|
.default(DEFAULT_CODER_SERVER_PORT));
|
|
42346
43146
|
command.option('--dry-run', 'Print unwritten prompts without executing', false);
|
|
42347
43147
|
addPromptRunnerSelectionOptions(command);
|
|
43148
|
+
addHarnessUpdateOption(command);
|
|
42348
43149
|
command.option('--agent <agent-book-path>', 'Path to a .book file whose compiled system message is prepended to each coding prompt');
|
|
42349
43150
|
command.option('--context <context-or-file>', 'Append extra instructions either inline or from a file path relative to the current project');
|
|
42350
43151
|
command.option('--test <test-command...>', 'Run a verification command after each prompt; quote it when the command itself contains top-level flags');
|
|
@@ -42376,7 +43177,8 @@
|
|
|
42376
43177
|
const runnerOptions = normalizePromptRunnerCliOptions(cliOptions, {
|
|
42377
43178
|
isAgentRequired: !dryRun,
|
|
42378
43179
|
});
|
|
42379
|
-
|
|
43180
|
+
const { isHarnessUpdateCheckEnabled } = normalizeHarnessUpdateCliOptions(cliOptions);
|
|
43181
|
+
await $ensureHarnessInstallations([runnerOptions.agentName], isHarnessUpdateCheckEnabled);
|
|
42380
43182
|
// [1] Parse the wait options and --no-auto (same logic as `coder run`)
|
|
42381
43183
|
const waitForUser = !auto;
|
|
42382
43184
|
const waitAfterPrompt = parseOptionalWaitDuration(waitAfterPromptValue, 0);
|
|
@@ -44300,23 +45102,27 @@
|
|
|
44300
45102
|
// TODO: [🧠][♿] Maybe export through `@promptbook/node`
|
|
44301
45103
|
|
|
44302
45104
|
/**
|
|
44303
|
-
* Attempts to locate the specified application on a Windows system by searching common installation directories.
|
|
45105
|
+
* Attempts to locate the specified application on a Windows system by searching PATH and common installation directories.
|
|
44304
45106
|
* Returns the path to the executable if found, or null otherwise.
|
|
44305
45107
|
*
|
|
44306
45108
|
* @private within the repository
|
|
44307
45109
|
*/
|
|
44308
45110
|
async function locateAppOnWindows({ appName, windowsSuffix, }) {
|
|
44309
45111
|
try {
|
|
44310
|
-
const
|
|
45112
|
+
const EXECUTABLE_FILENAME = windowsSuffix.replace(/^.*[\\/]/, '');
|
|
45113
|
+
const PATH_EXECUTABLE_PATHS = (process.env.PATH || '')
|
|
45114
|
+
.split(path.delimiter)
|
|
45115
|
+
.filter(Boolean)
|
|
45116
|
+
.map((pathPrefix) => path.join(pathPrefix, EXECUTABLE_FILENAME));
|
|
45117
|
+
const INSTALLATION_EXECUTABLE_PATHS = [
|
|
44311
45118
|
process.env.LOCALAPPDATA,
|
|
44312
45119
|
path.join(process.env.LOCALAPPDATA || '', 'Programs'),
|
|
44313
45120
|
process.env.PROGRAMFILES,
|
|
44314
45121
|
process.env['PROGRAMFILES(X86)'],
|
|
44315
|
-
];
|
|
44316
|
-
for (const
|
|
44317
|
-
|
|
44318
|
-
|
|
44319
|
-
return path;
|
|
45122
|
+
].map((pathPrefix) => pathPrefix + windowsSuffix);
|
|
45123
|
+
for (const executablePath of [...PATH_EXECUTABLE_PATHS, ...INSTALLATION_EXECUTABLE_PATHS]) {
|
|
45124
|
+
if (await isExecutable(executablePath, $provideFilesystemForNode())) {
|
|
45125
|
+
return executablePath;
|
|
44320
45126
|
}
|
|
44321
45127
|
}
|
|
44322
45128
|
throw new Error(`Can not locate app ${appName} on Windows.`);
|
|
@@ -75709,6 +76515,10 @@
|
|
|
75709
76515
|
* Constant for prompts dir.
|
|
75710
76516
|
*/
|
|
75711
76517
|
const PROMPTS_DIR$1 = path.join(process.cwd(), 'prompts');
|
|
76518
|
+
/**
|
|
76519
|
+
* Commit message for files changed by a successful or failed pre-coding test in repair mode.
|
|
76520
|
+
*/
|
|
76521
|
+
const PRE_CODING_TEST_CHANGES_COMMIT_MESSAGE = 'test: Apply changes made by pre-coding tests';
|
|
75712
76522
|
/**
|
|
75713
76523
|
* Main entry point for running prompts with the selected agent.
|
|
75714
76524
|
*
|
|
@@ -76032,6 +76842,7 @@
|
|
|
76032
76842
|
});
|
|
76033
76843
|
await ensureWorkingTreeClean();
|
|
76034
76844
|
}
|
|
76845
|
+
const testBeforeCommitScope = await captureTestBeforeCommitScopeIfNeeded(runOptions);
|
|
76035
76846
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.startCapturingAgentOutput();
|
|
76036
76847
|
const testBeforeResult = await runTestBefore({
|
|
76037
76848
|
testCommand: runOptions.testCommand,
|
|
@@ -76040,6 +76851,11 @@
|
|
|
76040
76851
|
}).finally(() => {
|
|
76041
76852
|
uiHandle === null || uiHandle === void 0 ? void 0 : uiHandle.stopCapturingAgentOutput();
|
|
76042
76853
|
});
|
|
76854
|
+
await commitTestBeforeChangesIfNeeded({
|
|
76855
|
+
runOptions,
|
|
76856
|
+
testBeforeCommitScope,
|
|
76857
|
+
waitForRequestedPause,
|
|
76858
|
+
});
|
|
76043
76859
|
if (testBeforeResult.isPassed) {
|
|
76044
76860
|
return hasWaitedForStart;
|
|
76045
76861
|
}
|
|
@@ -76088,6 +76904,38 @@
|
|
|
76088
76904
|
});
|
|
76089
76905
|
return updatedHasWaitedForStart;
|
|
76090
76906
|
}
|
|
76907
|
+
/**
|
|
76908
|
+
* Captures the files present before a `yes-and-fix` pre-coding test, so only changes made by that test can be committed.
|
|
76909
|
+
*/
|
|
76910
|
+
async function captureTestBeforeCommitScopeIfNeeded(runOptions) {
|
|
76911
|
+
if (runOptions.testBefore !== 'yes-and-fix' || runOptions.noCommit) {
|
|
76912
|
+
return undefined;
|
|
76913
|
+
}
|
|
76914
|
+
return captureCoderCommitScope(process.cwd());
|
|
76915
|
+
}
|
|
76916
|
+
/**
|
|
76917
|
+
* Commits files changed by a `yes-and-fix` pre-coding test before the coder continues to a queued or repair prompt.
|
|
76918
|
+
*/
|
|
76919
|
+
async function commitTestBeforeChangesIfNeeded(options) {
|
|
76920
|
+
const { runOptions, testBeforeCommitScope, waitForRequestedPause } = options;
|
|
76921
|
+
if (!testBeforeCommitScope) {
|
|
76922
|
+
return;
|
|
76923
|
+
}
|
|
76924
|
+
const relevantPaths = await resolveCoderCommitScopePaths(testBeforeCommitScope);
|
|
76925
|
+
if (relevantPaths.length === 0) {
|
|
76926
|
+
return;
|
|
76927
|
+
}
|
|
76928
|
+
await waitForRequestedPause({
|
|
76929
|
+
checkpointLabel: 'committing changes made by pre-coding tests',
|
|
76930
|
+
phase: 'verifying',
|
|
76931
|
+
statusMessage: 'Committing changes made by pre-coding tests...',
|
|
76932
|
+
});
|
|
76933
|
+
await commitChanges(PRE_CODING_TEST_CHANGES_COMMIT_MESSAGE, {
|
|
76934
|
+
autoPush: runOptions.autoPush,
|
|
76935
|
+
projectPath: testBeforeCommitScope.projectPath,
|
|
76936
|
+
relevantPaths,
|
|
76937
|
+
});
|
|
76938
|
+
}
|
|
76091
76939
|
/**
|
|
76092
76940
|
* Creates a pause waiter that keeps the progress display and rich UI in sync.
|
|
76093
76941
|
*/
|