@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.
Files changed (145) hide show
  1. package/apps/agents-server/src/app/admin/messages/MessagesClient.tsx +8 -1
  2. package/apps/agents-server/src/app/admin/messages/send-email/SendEmailClient.tsx +193 -63
  3. package/apps/agents-server/src/app/admin/messages/send-email/actions.ts +25 -28
  4. package/apps/agents-server/src/app/admin/messages/send-email/emailTesting.ts +153 -0
  5. package/apps/agents-server/src/app/admin/messages/send-email/emailTestingAccess.ts +30 -0
  6. package/apps/agents-server/src/app/admin/messages/send-email/page.tsx +18 -5
  7. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +7 -4
  8. package/apps/agents-server/src/app/agents/[agentName]/chat/AgentGoalChatPlannedMessages.tsx +23 -8
  9. package/apps/agents-server/src/app/agents/[agentName]/chat/CanonicalAgentChatSurface.tsx +14 -3
  10. package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +2 -20
  11. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +2 -1
  12. package/apps/agents-server/src/app/agents/[agentName]/projectReferenceActions.ts +61 -0
  13. package/apps/agents-server/src/app/api/internal/agent-goal-chat-planned-messages/route.ts +34 -7
  14. package/apps/agents-server/src/components/AgentProjects/resolveLatestCompletedAgentMessageKey.ts +32 -0
  15. package/apps/agents-server/src/components/AgentProjects/useAgentProjectMarkdownReferences.ts +124 -2
  16. package/apps/agents-server/src/languages/ServerTranslationKeys.ts +3 -0
  17. package/apps/agents-server/src/languages/translations/czech.yaml +3 -0
  18. package/apps/agents-server/src/languages/translations/english.yaml +3 -0
  19. package/apps/agents-server/src/message-providers/email/stalwart/StalwartMessageProvider.ts +2 -1
  20. package/apps/agents-server/src/tools/agentGoalChatTimeoutToolFunctions.ts +24 -2
  21. package/apps/agents-server/src/tools/agentGoalChatTimeoutTools.ts +5 -4
  22. package/apps/agents-server/src/utils/agentGoalChat/agentGoalChatPlannedMessageActions.ts +38 -9
  23. package/apps/agents-server/src/utils/agentGoalChat/createAgentGoalChatNoteContent.ts +15 -6
  24. package/apps/agents-server/src/utils/agentProjects/listAgentProjectNames.ts +35 -0
  25. package/apps/agents-server/src/utils/agentProjects/listAgentProjects.ts +6 -23
  26. package/apps/agents-server/src/utils/agentProjects/resolveAgentChatProjectReferences.ts +25 -0
  27. package/apps/agents-server/src/utils/chatMessageChips/createAnsweredMessageChipToolCalls.ts +37 -0
  28. package/apps/agents-server/src/utils/chatMessageChips/createPlannedMessageChipToolCalls.ts +39 -0
  29. package/apps/agents-server/src/utils/chatMessageChips/createTouchedProjectChipToolCalls.ts +75 -0
  30. package/apps/agents-server/src/utils/email/agentEmailAddress.ts +14 -0
  31. package/apps/agents-server/src/utils/email/sendEmailThroughStalwart.ts +2 -1
  32. package/apps/agents-server/src/utils/localChatRunner/applyLocalAgentPlannedMessageCommands.ts +212 -0
  33. package/apps/agents-server/src/utils/localChatRunner/prepareLocalAgentPlannedMessagesSidecar.ts +66 -0
  34. package/apps/agents-server/src/utils/localChatRunner/processLocalUserChatJob.ts +110 -22
  35. package/apps/agents-server/src/utils/userChat/persistUserChatJobTerminalState.ts +5 -0
  36. package/apps/agents-server/src/utils/userChat/userChatJobRunReport.ts +30 -0
  37. package/apps/agents-server/src/utils/userChatTimeout/createTimeoutWakeUpMessage.ts +9 -1
  38. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore/repeatFiredUserChatTimeout.ts +74 -0
  39. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutStore.ts +1 -0
  40. package/apps/agents-server/src/utils/userChatTimeout/userChatTimeoutWorker.ts +63 -54
  41. package/esm/index.es.js +1042 -194
  42. package/esm/index.es.js.map +1 -1
  43. package/esm/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +22 -4
  44. package/esm/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +3 -3
  45. package/esm/scripts/run-agent-messages/messages/loadAgentPlannedMessagesSidecar.d.ts +10 -0
  46. package/esm/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +15 -0
  47. package/esm/scripts/run-codex-prompts/common/runGoScript/$spawnLoggedBashScript.d.ts +25 -0
  48. package/esm/scripts/run-codex-prompts/common/runGoScript/$terminateLoggedBashProcessTree.d.ts +11 -0
  49. package/esm/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +4 -0
  50. package/esm/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +5 -0
  51. package/esm/src/book-2.0/agent-source/ParsedUnknownCommitment.d.ts +26 -0
  52. package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.unknown.test.d.ts +1 -0
  53. package/esm/src/book-2.0/agent-source/getBookCommitmentLineType.d.ts +19 -0
  54. package/esm/src/book-2.0/agent-source/parseAgentSourceWithCommitments.unknown.test.d.ts +1 -0
  55. package/esm/src/book-3.0/AgentMessageRunReport.d.ts +28 -0
  56. package/esm/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +94 -0
  57. package/esm/src/book-3.0/AgentPlannedMessagesSidecar.test.d.ts +1 -0
  58. package/esm/src/book-3.0/createAgentMessageSidecarBaseName.d.ts +13 -0
  59. package/esm/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.d.ts +28 -0
  60. package/esm/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.test.d.ts +1 -0
  61. package/esm/src/book-components/Chat/utils/agentProjectToolCall.d.ts +46 -0
  62. package/esm/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +24 -0
  63. package/esm/src/cli/cli-commands/common/harness/$checkHarnessInstallation.d.ts +3 -3
  64. package/esm/src/cli/cli-commands/common/harness/$checkHarnessInstallation.test.d.ts +1 -0
  65. package/esm/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +3 -3
  66. package/esm/src/cli/cli-commands/common/harness/HarnessInstallationStatus.d.ts +3 -2
  67. package/esm/src/cli/cli-commands/common/harnessUpdateCliOptions.d.ts +29 -0
  68. package/esm/src/cli/cli-commands/common/harnessUpdateCliOptions.test.d.ts +1 -0
  69. package/esm/src/executables/platforms/locateAppOnWindows.d.ts +1 -1
  70. package/esm/src/executables/platforms/locateAppOnWindows.test.d.ts +1 -0
  71. package/esm/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +59 -0
  72. package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.d.ts +19 -0
  73. package/esm/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.test.d.ts +1 -0
  74. package/esm/src/version.d.ts +1 -1
  75. package/package.json +1 -1
  76. package/src/book-2.0/agent-source/AgentSourceParseResult.ts +6 -0
  77. package/src/book-2.0/agent-source/ParsedUnknownCommitment.ts +29 -0
  78. package/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.ts +38 -1
  79. package/src/book-2.0/agent-source/getBookCommitmentLineType.ts +36 -0
  80. package/src/book-2.0/agent-source/parseAgentSourceWithCommitments.ts +128 -61
  81. package/src/book-3.0/AgentMessageRunReport.ts +76 -0
  82. package/src/book-3.0/AgentPlannedMessagesSidecar.ts +229 -0
  83. package/src/book-3.0/AgentTeamConversationWorkspace.ts +3 -5
  84. package/src/book-3.0/createAgentMessageSidecarBaseName.ts +20 -0
  85. package/src/book-components/BookEditor/BookEditorMonaco.tsx +6 -1
  86. package/src/book-components/BookEditor/BookEditorMonacoTokenization.ts +3 -1
  87. package/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.ts +50 -0
  88. package/src/book-components/Chat/Chat/Chat.module.css +6 -1
  89. package/src/book-components/Chat/Chat/renderToolCallDetails.tsx +1 -12
  90. package/src/book-components/Chat/utils/agentProjectToolCall.ts +74 -0
  91. package/src/book-components/Chat/utils/getToolCallChipletInfo.ts +28 -0
  92. package/src/book-components/Chat/utils/timeoutToolCallPresentation.ts +23 -3
  93. package/src/cli/cli-commands/coder/boilerplateTemplates.ts +3 -15
  94. package/src/cli/cli-commands/coder/init.ts +11 -2
  95. package/src/cli/cli-commands/coder/ping.ts +11 -1
  96. package/src/cli/cli-commands/coder/run.ts +11 -2
  97. package/src/cli/cli-commands/coder/server.ts +11 -2
  98. package/src/cli/cli-commands/common/harness/$applyHarnessInstallationStatus.ts +5 -0
  99. package/src/cli/cli-commands/common/harness/$checkHarnessInstallation.ts +17 -5
  100. package/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.ts +6 -3
  101. package/src/cli/cli-commands/common/harness/HarnessInstallationStatus.ts +3 -2
  102. package/src/cli/cli-commands/common/harnessUpdateCliOptions.ts +49 -0
  103. package/src/executables/platforms/locateAppOnWindows.ts +12 -9
  104. package/src/other/templates/getTemplatesPipelineCollection.ts +740 -860
  105. package/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.ts +105 -0
  106. package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +6 -54
  107. package/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.ts +147 -0
  108. package/src/version.ts +2 -2
  109. package/src/versions.txt +2 -1
  110. package/umd/index.umd.js +1041 -193
  111. package/umd/index.umd.js.map +1 -1
  112. package/umd/scripts/run-agent-messages/messages/buildAgentGoalChatPromptSection.d.ts +22 -4
  113. package/umd/scripts/run-agent-messages/messages/buildAgentMessagePrompt.d.ts +3 -3
  114. package/umd/scripts/run-agent-messages/messages/loadAgentPlannedMessagesSidecar.d.ts +10 -0
  115. package/umd/scripts/run-agent-messages/messages/resolveTouchedAgentProjects.d.ts +15 -0
  116. package/umd/scripts/run-codex-prompts/common/runGoScript/$spawnLoggedBashScript.d.ts +25 -0
  117. package/umd/scripts/run-codex-prompts/common/runGoScript/$terminateLoggedBashProcessTree.d.ts +11 -0
  118. package/umd/scripts/run-codex-prompts/common/runGoScript/scriptExecutionLog.d.ts +4 -0
  119. package/umd/src/book-2.0/agent-source/AgentSourceParseResult.d.ts +5 -0
  120. package/umd/src/book-2.0/agent-source/ParsedUnknownCommitment.d.ts +26 -0
  121. package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.unknown.test.d.ts +1 -0
  122. package/umd/src/book-2.0/agent-source/getBookCommitmentLineType.d.ts +19 -0
  123. package/umd/src/book-2.0/agent-source/parseAgentSourceWithCommitments.unknown.test.d.ts +1 -0
  124. package/umd/src/book-3.0/AgentMessageRunReport.d.ts +28 -0
  125. package/umd/src/book-3.0/AgentPlannedMessagesSidecar.d.ts +94 -0
  126. package/umd/src/book-3.0/AgentPlannedMessagesSidecar.test.d.ts +1 -0
  127. package/umd/src/book-3.0/createAgentMessageSidecarBaseName.d.ts +13 -0
  128. package/umd/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.d.ts +28 -0
  129. package/umd/src/book-components/BookEditor/createUnknownCommitmentDiagnostics.test.d.ts +1 -0
  130. package/umd/src/book-components/Chat/utils/agentProjectToolCall.d.ts +46 -0
  131. package/umd/src/book-components/Chat/utils/timeoutToolCallPresentation.d.ts +24 -0
  132. package/umd/src/cli/cli-commands/common/harness/$checkHarnessInstallation.d.ts +3 -3
  133. package/umd/src/cli/cli-commands/common/harness/$checkHarnessInstallation.test.d.ts +1 -0
  134. package/umd/src/cli/cli-commands/common/harness/$ensureHarnessInstallations.d.ts +3 -3
  135. package/umd/src/cli/cli-commands/common/harness/HarnessInstallationStatus.d.ts +3 -2
  136. package/umd/src/cli/cli-commands/common/harnessUpdateCliOptions.d.ts +29 -0
  137. package/umd/src/cli/cli-commands/common/harnessUpdateCliOptions.test.d.ts +1 -0
  138. package/umd/src/executables/platforms/locateAppOnWindows.d.ts +1 -1
  139. package/umd/src/executables/platforms/locateAppOnWindows.test.d.ts +1 -0
  140. package/umd/src/utils/agent-message-runtime/parseAgentMessageRuntimeLogEvents.d.ts +59 -0
  141. package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.d.ts +19 -0
  142. package/umd/src/utils/agent-message-runtime/resolveAgentMessageTouchedProjectNames.test.d.ts +1 -0
  143. package/umd/src/version.d.ts +1 -1
  144. package/esm/apps/agents-server/src/utils/agentGoalChat/agentGoalChatConstants.d.ts +0 -12
  145. package/umd/apps/agents-server/src/utils/agentGoalChat/agentGoalChatConstants.d.ts +0 -12
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Resolves which projects one coding harness touched while answering a single message.
3
+ *
4
+ * The runtime log streams what the harness really did, so a project counts as touched when the
5
+ * harness named it in a tool invocation — reading, searching, running, or editing files inside
6
+ * `projects/<project-name>/`. Only tool payloads are inspected: tool results and assistant
7
+ * narration are ignored so a project merely mentioned in the conversation is never reported.
8
+ *
9
+ * Every candidate is matched against the projects that really exist, which both filters prompt
10
+ * placeholders such as `projects/<project-name>/` and keeps the reported names canonical.
11
+ *
12
+ * @param options - Raw runtime log content and the project directory names of the agent.
13
+ * @returns Touched project names in the canonical spelling, ordered by first appearance.
14
+ * @private internal utility of the agent-message runtime
15
+ */
16
+ export declare function resolveAgentMessageTouchedProjectNames(options: {
17
+ readonly logText: string | null | undefined;
18
+ readonly knownProjectNames: ReadonlyArray<string>;
19
+ }): ReadonlyArray<string>;
@@ -15,7 +15,7 @@ export declare const BOOK_LANGUAGE_VERSION: string_semantic_version;
15
15
  export declare const PROMPTBOOK_ENGINE_VERSION: string_promptbook_version;
16
16
  /**
17
17
  * Represents the version string of the Promptbook engine.
18
- * It follows semantic versioning (e.g., `0.114.0-10`).
18
+ * It follows semantic versioning (e.g., `0.114.0-12`).
19
19
  *
20
20
  * @generated
21
21
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptbook/cli",
3
- "version": "0.114.0-11",
3
+ "version": "0.114.0-13",
4
4
  "description": "Promptbook: Create persistent AI agents that turn your company's scattered knowledge into action",
5
5
  "private": false,
6
6
  "sideEffects": false,
@@ -1,5 +1,6 @@
1
1
  import type { ParsedCommitment } from '../../commitments/_base/ParsedCommitment';
2
2
  import type { string_agent_name } from '../../types/string_agent_name';
3
+ import type { ParsedUnknownCommitment } from './ParsedUnknownCommitment';
3
4
 
4
5
  /**
5
6
  * Result of parsing agent source for commitments
@@ -22,6 +23,11 @@ export type AgentSourceParseResult = {
22
23
  */
23
24
  commitments: ParsedCommitment[];
24
25
 
26
+ /**
27
+ * Uppercase commitment blocks whose types are not registered by Promptbook.
28
+ */
29
+ unknownCommitments: ParsedUnknownCommitment[];
30
+
25
31
  /**
26
32
  * Lines that are not commitments (for system message)
27
33
  */
@@ -0,0 +1,29 @@
1
+ /**
2
+ * An uppercase Book commitment block whose keyword is not registered by Promptbook.
3
+ *
4
+ * Unknown commitments are retained as system-message context instead of being applied
5
+ * as executable commitments.
6
+ *
7
+ * @private internal type of `parseAgentSourceWithCommitments`
8
+ */
9
+ export type ParsedUnknownCommitment = {
10
+ /**
11
+ * Uppercase unknown commitment type, for example `FOO` or `BAR BZZ`.
12
+ */
13
+ readonly type: string;
14
+
15
+ /**
16
+ * Original first line, retained for precise editor diagnostics.
17
+ */
18
+ readonly originalLine: string;
19
+
20
+ /**
21
+ * Line number in the agent source (1-based).
22
+ */
23
+ readonly lineNumber: number;
24
+
25
+ /**
26
+ * Complete unknown commitment block, including its keyword and continuation lines.
27
+ */
28
+ readonly source: string;
29
+ };
@@ -46,8 +46,9 @@ export async function augmentAgentModelRequirementsFromSource(
46
46
  requirements = await importReferencedFiles(requirements);
47
47
  requirements = appendMcpServers(requirements, agentSource);
48
48
  requirements = appendNonCommitmentContent(requirements, parseResult);
49
+ requirements = appendExampleInteractions(requirements, parseResult);
49
50
 
50
- return appendExampleInteractions(requirements, parseResult);
51
+ return appendUnknownCommitmentContent(requirements, parseResult);
51
52
  }
52
53
 
53
54
  /**
@@ -188,6 +189,42 @@ function appendNonCommitmentContent(
188
189
  return appendSystemMessageSection(requirements, nonCommitmentContent);
189
190
  }
190
191
 
192
+ /**
193
+ * Appends unknown commitment blocks as final extra context without applying commitment side effects.
194
+ *
195
+ * @param requirements - Current requirements snapshot.
196
+ * @param parseResult - Parsed source including unknown commitment blocks.
197
+ * @returns Requirements with unknown commitment context appended at the end of the system message.
198
+ *
199
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
200
+ */
201
+ function appendUnknownCommitmentContent(
202
+ requirements: AgentModelRequirements,
203
+ parseResult: ParsedAgentSourceWithCommitments,
204
+ ): AgentModelRequirements {
205
+ const unknownCommitmentContent = getUnknownCommitmentContent(parseResult);
206
+ if (!unknownCommitmentContent) {
207
+ return requirements;
208
+ }
209
+
210
+ return appendSystemMessageSection(requirements, unknownCommitmentContent);
211
+ }
212
+
213
+ /**
214
+ * Joins unknown commitment blocks into their final extra-context representation.
215
+ *
216
+ * @param parseResult - Parsed source including unknown commitment blocks.
217
+ * @returns Unknown commitment source blocks in their original order.
218
+ *
219
+ * @private internal utility of `appendUnknownCommitmentContent`
220
+ */
221
+ function getUnknownCommitmentContent(parseResult: ParsedAgentSourceWithCommitments): string {
222
+ return parseResult.unknownCommitments
223
+ .map((commitment) => commitment.source)
224
+ .filter(Boolean)
225
+ .join('\n\n');
226
+ }
227
+
191
228
  /**
192
229
  * Collects plain-text lines that were not parsed as commitments and should still become part of the final system message.
193
230
  *
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Pattern shared by Book parsing and editor highlighting for a commitment-like line.
3
+ *
4
+ * A Book commitment keyword consists of one or more all-uppercase words with at least
5
+ * two characters each. This deliberately mirrors the Book editor syntax rule so an
6
+ * unknown keyword starts a new source block everywhere it is interpreted.
7
+ *
8
+ * @private internal constant of `getBookCommitmentLineType`
9
+ */
10
+ const BOOK_COMMITMENT_LINE_TYPE_REGEX = /^\s*(?<type>[A-Z][A-Z0-9]+(?:\s+[A-Z][A-Z0-9]+)*)(?=\s|$)/;
11
+
12
+ /**
13
+ * Creates the regex used to recognize the uppercase commitment type at the beginning of a Book line.
14
+ *
15
+ * A fresh regular expression keeps Monaco tokenizer state isolated from parser calls.
16
+ *
17
+ * @returns Regular expression matching one Book commitment-like line.
18
+ *
19
+ * @private internal utility of Book parsing and `<BookEditor/>`
20
+ */
21
+ export function createBookCommitmentLineTypeRegex(): RegExp {
22
+ return new RegExp(BOOK_COMMITMENT_LINE_TYPE_REGEX.source);
23
+ }
24
+
25
+ /**
26
+ * Extracts the uppercase commitment type from a Book line, including types not registered by Promptbook.
27
+ *
28
+ * @param line - One raw Book source line.
29
+ * @returns Matched commitment type or `null` when the line does not begin with commitment syntax.
30
+ *
31
+ * @private internal utility of Book parsing and `<BookEditor/>`
32
+ */
33
+ export function getBookCommitmentLineType(line: string): string | null {
34
+ const match = BOOK_COMMITMENT_LINE_TYPE_REGEX.exec(line);
35
+ return match?.groups?.type || null;
36
+ }
@@ -3,7 +3,9 @@ import type { BookCommitment } from '../../commitments/_base/BookCommitment';
3
3
  import type { ParsedCommitment } from '../../commitments/_base/ParsedCommitment';
4
4
  import { COMMITMENT_REGISTRY } from '../../commitments/index';
5
5
  import type { AgentSourceParseResult } from './AgentSourceParseResult';
6
+ import { getBookCommitmentLineType } from './getBookCommitmentLineType';
6
7
  import { parseAgentSourcePrelude } from './parseAgentSourcePrelude';
8
+ import type { ParsedUnknownCommitment } from './ParsedUnknownCommitment';
7
9
  import type { string_book } from './string_book';
8
10
 
9
11
  /**
@@ -12,6 +14,39 @@ import type { string_book } from './string_book';
12
14
  */
13
15
  const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
14
16
 
17
+ /**
18
+ * Registered commitment block currently being collected from Book source.
19
+ *
20
+ * @private internal type of `parseAgentSourceWithCommitments`
21
+ */
22
+ type CurrentKnownCommitment = {
23
+ readonly kind: 'known';
24
+ readonly type: string;
25
+ readonly startLineNumber: number;
26
+ readonly originalStartLine: string;
27
+ readonly contentLines: string[];
28
+ };
29
+
30
+ /**
31
+ * Unknown commitment block currently being collected from Book source.
32
+ *
33
+ * @private internal type of `parseAgentSourceWithCommitments`
34
+ */
35
+ type CurrentUnknownCommitment = {
36
+ readonly kind: 'unknown';
37
+ readonly type: string;
38
+ readonly startLineNumber: number;
39
+ readonly originalStartLine: string;
40
+ readonly sourceLines: string[];
41
+ };
42
+
43
+ /**
44
+ * Commitment-like source block currently being collected.
45
+ *
46
+ * @private internal type of `parseAgentSourceWithCommitments`
47
+ */
48
+ type CurrentCommitment = CurrentKnownCommitment | CurrentUnknownCommitment;
49
+
15
50
  /**
16
51
  * Parses agent source using the new commitment system with multiline support
17
52
  * This function replaces the hardcoded commitment parsing in the original parseAgentSource
@@ -26,6 +61,7 @@ export function parseAgentSourceWithCommitments(agentSource: string_book): Omit<
26
61
  return {
27
62
  agentName: null,
28
63
  commitments: [],
64
+ unknownCommitments: [],
29
65
  nonCommitmentLines: [],
30
66
  };
31
67
  }
@@ -33,15 +69,11 @@ export function parseAgentSourceWithCommitments(agentSource: string_book): Omit<
33
69
  const { lines, agentName, agentNameLineIndex, agentNameLineNumber } = parseAgentSourcePrelude(agentSource);
34
70
 
35
71
  const commitments: ParsedCommitment[] = [];
72
+ const unknownCommitments: ParsedUnknownCommitment[] = [];
36
73
  const nonCommitmentLines: string[] = agentNameLineIndex >= 0 ? [lines[agentNameLineIndex]!] : [];
37
74
 
38
- // Parse commitments with multiline support
39
- let currentCommitment: {
40
- type: string;
41
- startLineNumber: number;
42
- originalStartLine: string;
43
- contentLines: string[];
44
- } | null = null;
75
+ // Parse commitments with multiline support.
76
+ let currentCommitment: CurrentCommitment | null = null;
45
77
 
46
78
  // Process lines starting from after the agent name line
47
79
  const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
@@ -58,24 +90,12 @@ export function parseAgentSourceWithCommitments(agentSource: string_book): Omit<
58
90
  if (trimmedLine.startsWith('```')) {
59
91
  isInsideCodeBlock = !isInsideCodeBlock;
60
92
 
61
- if (currentCommitment) {
62
- // If we are inside a commitment, the code block is part of it
63
- currentCommitment.contentLines.push(line);
64
- } else {
65
- // If we are not inside a commitment, the code block is non-commitment
66
- nonCommitmentLines.push(line);
67
- }
93
+ appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
68
94
  continue;
69
95
  }
70
96
 
71
97
  if (isInsideCodeBlock) {
72
- if (currentCommitment) {
73
- // If we are inside a commitment and a code block, the line is part of the commitment
74
- currentCommitment.contentLines.push(line);
75
- } else {
76
- // If we are inside a code block but not a commitment, the line is non-commitment
77
- nonCommitmentLines.push(line);
78
- }
98
+ appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
79
99
  continue;
80
100
  }
81
101
 
@@ -86,16 +106,7 @@ export function parseAgentSourceWithCommitments(agentSource: string_book): Omit<
86
106
  const match = typeRegex.exec(line.trim());
87
107
 
88
108
  if (match && match.groups?.type) {
89
- // Save the previous commitment if it exists
90
- if (currentCommitment) {
91
- const fullContent = currentCommitment.contentLines.join('\n');
92
- commitments.push({
93
- type: currentCommitment.type as BookCommitment,
94
- content: spaceTrim(fullContent),
95
- originalLine: currentCommitment.originalStartLine,
96
- lineNumber: currentCommitment.startLineNumber,
97
- });
98
- }
109
+ appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
99
110
 
100
111
  // Extract the initial content from the commitment line
101
112
  const fullRegex = definition.createRegex();
@@ -104,6 +115,7 @@ export function parseAgentSourceWithCommitments(agentSource: string_book): Omit<
104
115
 
105
116
  // Start a new commitment
106
117
  currentCommitment = {
118
+ kind: 'known',
107
119
  type: definition.type,
108
120
  startLineNumber: i + 1,
109
121
  originalStartLine: line,
@@ -114,51 +126,106 @@ export function parseAgentSourceWithCommitments(agentSource: string_book): Omit<
114
126
  }
115
127
  }
116
128
 
129
+ if (foundNewCommitment) {
130
+ continue;
131
+ }
132
+
133
+ const unknownCommitmentType = getBookCommitmentLineType(line);
134
+ if (unknownCommitmentType) {
135
+ appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
136
+ currentCommitment = {
137
+ kind: 'unknown',
138
+ type: unknownCommitmentType,
139
+ startLineNumber: i + 1,
140
+ originalStartLine: line,
141
+ sourceLines: [line],
142
+ };
143
+ continue;
144
+ }
145
+
117
146
  // Check if this is a horizontal line (ends any current commitment)
118
147
  const isHorizontalLine = HORIZONTAL_LINE_PATTERN.test(line);
119
148
  if (isHorizontalLine) {
120
- // Save the current commitment if it exists
121
- if (currentCommitment) {
122
- const fullContent = currentCommitment.contentLines.join('\n');
123
- commitments.push({
124
- type: currentCommitment.type as BookCommitment,
125
- content: spaceTrim(fullContent),
126
- originalLine: currentCommitment.originalStartLine,
127
- lineNumber: currentCommitment.startLineNumber,
128
- });
129
- currentCommitment = null;
130
- }
149
+ appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
150
+ currentCommitment = null;
131
151
  // Add horizontal line to non-commitment lines
132
152
  nonCommitmentLines.push(line);
133
153
  continue;
134
154
  }
135
155
 
136
- if (!foundNewCommitment) {
137
- if (currentCommitment) {
138
- // This line belongs to the current commitment
139
- currentCommitment.contentLines.push(line);
140
- } else {
141
- // This line is not part of any commitment
142
- nonCommitmentLines.push(line);
143
- }
144
- }
156
+ appendLineToCurrentCommitmentOrNonCommitmentLines(currentCommitment, line, nonCommitmentLines);
145
157
  }
146
158
 
147
- // Don't forget to save the last commitment if it exists
148
- if (currentCommitment) {
149
- const fullContent = currentCommitment.contentLines.join('\n');
150
- commitments.push({
151
- type: currentCommitment.type as BookCommitment,
152
- content: spaceTrim(fullContent) as BookCommitment,
153
- originalLine: currentCommitment.originalStartLine,
154
- lineNumber: currentCommitment.startLineNumber,
155
- });
156
- }
159
+ appendCurrentCommitment(currentCommitment, commitments, unknownCommitments);
157
160
 
158
161
  return {
159
162
  agentName,
160
163
  agentNameLineNumber,
161
164
  commitments,
165
+ unknownCommitments,
162
166
  nonCommitmentLines,
163
167
  };
164
168
  }
169
+
170
+ /**
171
+ * Stores the current known or unknown commitment in its appropriate parsed collection.
172
+ *
173
+ * @param currentCommitment - Commitment-like block collected so far.
174
+ * @param commitments - Parsed registered commitments to append to.
175
+ * @param unknownCommitments - Parsed unregistered commitments to append to.
176
+ *
177
+ * @private internal utility of `parseAgentSourceWithCommitments`
178
+ */
179
+ function appendCurrentCommitment(
180
+ currentCommitment: CurrentCommitment | null,
181
+ commitments: ParsedCommitment[],
182
+ unknownCommitments: ParsedUnknownCommitment[],
183
+ ): void {
184
+ if (!currentCommitment) {
185
+ return;
186
+ }
187
+
188
+ if (currentCommitment.kind === 'unknown') {
189
+ unknownCommitments.push({
190
+ type: currentCommitment.type,
191
+ originalLine: currentCommitment.originalStartLine,
192
+ lineNumber: currentCommitment.startLineNumber,
193
+ source: spaceTrim(currentCommitment.sourceLines.join('\n')),
194
+ });
195
+ return;
196
+ }
197
+
198
+ commitments.push({
199
+ type: currentCommitment.type as BookCommitment,
200
+ content: spaceTrim(currentCommitment.contentLines.join('\n')),
201
+ originalLine: currentCommitment.originalStartLine,
202
+ lineNumber: currentCommitment.startLineNumber,
203
+ });
204
+ }
205
+
206
+ /**
207
+ * Adds one source line to the active commitment-like block, or to plain source content when none is active.
208
+ *
209
+ * @param currentCommitment - Commitment-like block currently being collected.
210
+ * @param line - Source line to append.
211
+ * @param nonCommitmentLines - Plain source lines to append to when no block is active.
212
+ *
213
+ * @private internal utility of `parseAgentSourceWithCommitments`
214
+ */
215
+ function appendLineToCurrentCommitmentOrNonCommitmentLines(
216
+ currentCommitment: CurrentCommitment | null,
217
+ line: string,
218
+ nonCommitmentLines: string[],
219
+ ): void {
220
+ if (!currentCommitment) {
221
+ nonCommitmentLines.push(line);
222
+ return;
223
+ }
224
+
225
+ if (currentCommitment.kind === 'unknown') {
226
+ currentCommitment.sourceLines.push(line);
227
+ return;
228
+ }
229
+
230
+ currentCommitment.contentLines.push(line);
231
+ }
@@ -13,6 +13,25 @@ import type { CodexLoginMethod } from './codexLoginMethod';
13
13
  */
14
14
  export const AGENT_MESSAGE_RUN_REPORT_FILE_SUFFIX = '.report.json';
15
15
 
16
+ /**
17
+ * Exact wall-clock interval during which one harness processed an agent message.
18
+ *
19
+ * Note: [🚉] This is fully serializable as JSON
20
+ *
21
+ * @private internal type of the agent folder convention
22
+ */
23
+ export type AgentMessageRunExecutionTiming = {
24
+ /**
25
+ * ISO 8601 timestamp captured immediately before the harness begins the message.
26
+ */
27
+ readonly startedAt: string;
28
+
29
+ /**
30
+ * ISO 8601 timestamp captured when the harness finishes the message.
31
+ */
32
+ readonly finishedAt: string;
33
+ };
34
+
16
35
  /**
17
36
  * Report describing how one queued agent message was answered by a CLI harness runner.
18
37
  *
@@ -52,6 +71,19 @@ export type AgentMessageRunReport = {
52
71
  * Usage statistics of the run (price, token counts, duration).
53
72
  */
54
73
  readonly usage: Usage;
74
+
75
+ /**
76
+ * Measured wall-clock timing of the actual harness execution, excluding time spent waiting in the queue.
77
+ */
78
+ readonly executionTiming?: AgentMessageRunExecutionTiming;
79
+
80
+ /**
81
+ * Directory names of the agent projects the harness worked with while answering the message.
82
+ *
83
+ * Reported by the runner from its live runtime log, which is deleted once the message is
84
+ * answered, so this is the only trace of the projects one answer viewed or edited.
85
+ */
86
+ readonly touchedProjectNames?: ReadonlyArray<string>;
55
87
  };
56
88
 
57
89
  /**
@@ -110,9 +142,53 @@ export function normalizeAgentMessageRunReport(value: unknown): AgentMessageRunR
110
142
  return null;
111
143
  }
112
144
 
145
+ if (report.executionTiming !== undefined && !isSerializedAgentMessageRunExecutionTiming(report.executionTiming)) {
146
+ return null;
147
+ }
148
+
149
+ if (report.touchedProjectNames !== undefined && !isSerializedProjectNameList(report.touchedProjectNames)) {
150
+ return null;
151
+ }
152
+
113
153
  return report as AgentMessageRunReport;
114
154
  }
115
155
 
156
+ /**
157
+ * Checks that one value structurally matches a list of project directory names.
158
+ *
159
+ * @private internal helper of `normalizeAgentMessageRunReport`
160
+ */
161
+ function isSerializedProjectNameList(value: unknown): value is ReadonlyArray<string> {
162
+ return Array.isArray(value) && value.every((projectName) => typeof projectName === 'string');
163
+ }
164
+
165
+ /**
166
+ * Checks that one value contains a valid, non-negative agent-message execution interval.
167
+ *
168
+ * @private internal helper of `normalizeAgentMessageRunReport`
169
+ */
170
+ function isSerializedAgentMessageRunExecutionTiming(value: unknown): value is AgentMessageRunExecutionTiming {
171
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
172
+ return false;
173
+ }
174
+
175
+ const executionTiming = value as Record<string, unknown>;
176
+ if (!isSerializedIsoTimestamp(executionTiming.startedAt) || !isSerializedIsoTimestamp(executionTiming.finishedAt)) {
177
+ return false;
178
+ }
179
+
180
+ return Date.parse(executionTiming.finishedAt) >= Date.parse(executionTiming.startedAt);
181
+ }
182
+
183
+ /**
184
+ * Checks that one JSON value is a parseable ISO timestamp.
185
+ *
186
+ * @private internal helper of `normalizeAgentMessageRunReport`
187
+ */
188
+ function isSerializedIsoTimestamp(value: unknown): value is string {
189
+ return typeof value === 'string' && value.length > 0 && Number.isFinite(Date.parse(value));
190
+ }
191
+
116
192
  /**
117
193
  * Parses one run-report sidecar file content.
118
194
  *