@promptbook/cli 0.114.0-0 → 0.114.0-2

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 (113) hide show
  1. package/README.md +16 -15
  2. package/apps/agents-server/package.json +6 -4
  3. package/apps/agents-server/playwright.config.ts +28 -38
  4. package/apps/agents-server/scripts/build-agents-server.js +62 -0
  5. package/apps/agents-server/scripts/build-e2e.js +38 -0
  6. package/apps/agents-server/scripts/ensure-root-dependencies.js +86 -0
  7. package/apps/agents-server/scripts/prerender-homepage.js +1 -1
  8. package/apps/agents-server/scripts/run-e2e-tests.js +34 -0
  9. package/apps/agents-server/scripts/run-npm.js +42 -0
  10. package/apps/agents-server/src/app/admin/email-server/page.tsx +14 -6
  11. package/apps/agents-server/src/app/api/elevenlabs/tts/route.ts +3 -3
  12. package/apps/agents-server/src/app/api/onboarding/book/route.ts +7 -6
  13. package/apps/agents-server/src/app/superadmin/servers/ServersRegistryTable.tsx +105 -102
  14. package/apps/agents-server/src/app/superadmin/servers/useServersRegistryState.ts +15 -7
  15. package/apps/agents-server/src/components/AgentProjectDnsInstructions/AgentProjectDnsInstructions.tsx +11 -11
  16. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/ManGoBookEditor.tsx +82 -0
  17. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/WizardShell.tsx +2 -2
  18. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/BookStep.tsx +13 -16
  19. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/steps/ZadaniStep.tsx +4 -4
  20. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/config/bookSections.ts +23 -16
  21. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/lib/bookSource.ts +54 -0
  22. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/bookService.ts +15 -8
  23. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoAgentSource.ts +3 -37
  24. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/createManGoOpenEditorRequest.ts +1 -1
  25. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/state/OnboardingProvider.tsx +2 -2
  26. package/apps/agents-server/src/components/UsersList/CreateUserDialog.tsx +13 -22
  27. package/apps/agents-server/src/components/UsersList/PasswordGeneratorDialog.tsx +216 -0
  28. package/apps/agents-server/src/components/UsersList/UsersList.tsx +16 -11
  29. package/apps/agents-server/src/components/UsersList/generateSecurePassword.ts +112 -24
  30. package/apps/agents-server/src/components/UsersList/userDialogClassNames.ts +11 -0
  31. package/apps/agents-server/src/languages/ServerTranslationKeys.ts +11 -0
  32. package/apps/agents-server/src/languages/translations/czech.yaml +11 -0
  33. package/apps/agents-server/src/languages/translations/english.yaml +11 -0
  34. package/apps/agents-server/src/utils/agentProjects/agentProjectHrefs.ts +11 -0
  35. package/apps/agents-server/src/utils/agentProjects/createAgentProjectDnsRecords.ts +53 -7
  36. package/apps/agents-server/src/utils/agentProjects/createAgentProjectMarkdownReferences.ts +37 -27
  37. package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentBooks.ts +2 -13
  38. package/apps/agents-server/src/utils/manGoOnboarding/manGoOnboardingAgentRuntime.ts +21 -73
  39. package/apps/agents-server/src/utils/stalwart/createEmailDnsInstructions.ts +9 -5
  40. package/apps/agents-server/src/utils/stalwart/readStalwartEmailSnapshot.ts +23 -5
  41. package/apps/agents-server/src/utils/stalwart/stalwartBootstrap.ts +2 -1
  42. package/apps/agents-server/src/utils/stalwart/stalwartMailBridge.ts +7 -0
  43. package/apps/agents-server/tests/e2e/e2eEnvironment.cjs +49 -0
  44. package/esm/index.es.js +523 -169
  45. package/esm/index.es.js.map +1 -1
  46. package/esm/scripts/run-agent-chat/runCoderPing.d.ts +48 -0
  47. package/esm/scripts/run-codex-prompts/prompts/findNextTodoPrompt.d.ts +2 -1
  48. package/esm/scripts/run-codex-prompts/prompts/isPromptCompatibleWithRunner.d.ts +27 -0
  49. package/esm/scripts/run-codex-prompts/prompts/listRunnablePrompts.d.ts +2 -1
  50. package/esm/scripts/run-codex-prompts/prompts/listUpcomingTasks.d.ts +2 -1
  51. package/esm/scripts/run-codex-prompts/prompts/replacePromptTodoStatusLine.d.ts +7 -0
  52. package/esm/scripts/run-codex-prompts/testing/TestBeforeMode.d.ts +16 -0
  53. package/esm/scripts/run-codex-prompts/testing/createTestBeforeRepairPrompt.d.ts +9 -0
  54. package/esm/scripts/run-codex-prompts/testing/limitTestOutput.d.ts +4 -0
  55. package/esm/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -2
  56. package/esm/scripts/run-codex-prompts/testing/runTestBefore.d.ts +24 -0
  57. package/esm/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -0
  58. package/esm/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.d.ts +1 -15
  59. package/esm/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.d.ts +1 -1
  60. package/esm/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.d.ts +0 -4
  61. package/esm/src/book-components/Chat/utils/renderMarkdown.d.ts +7 -0
  62. package/esm/src/cli/cli-commands/coder/agentCodingFile.d.ts +2 -3
  63. package/esm/src/cli/cli-commands/coder/ping.d.ts +13 -0
  64. package/esm/src/cli/cli-commands/coder/ping.test.d.ts +1 -0
  65. package/esm/src/cli/cli-commands/coder.d.ts +1 -0
  66. package/package.json +1 -1
  67. package/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.ts +1 -15
  68. package/src/book-2.0/book-language-documentation/bookLanguageDocumentationExamples.ts +1 -2
  69. package/src/book-2.0/book-language-documentation/createStandaloneBookLanguageMarkdown.ts +92 -32
  70. package/src/book-2.0/book-language-documentation/czechBookLanguageManualDictionary.ts +16 -39
  71. package/src/book-2.0/book-language-documentation/englishBookLanguageManualDictionary.ts +16 -36
  72. package/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.ts +9 -1
  73. package/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.ts +4 -51
  74. package/src/book-2.0/book-language-documentation/renderGroupedCommitmentDocumentationMarkdown.ts +291 -4
  75. package/src/book-components/Chat/utils/renderMarkdown.ts +133 -9
  76. package/src/cli/cli-commands/agents-server/startAgentsServer/createLocalAgentRunOptions.ts +1 -0
  77. package/src/cli/cli-commands/coder/agentCodingFile.ts +6 -129
  78. package/src/cli/cli-commands/coder/getDefaultCoderPackageJsonScripts.ts +1 -1
  79. package/src/cli/cli-commands/coder/initializeCoderProjectConfiguration.ts +1 -4
  80. package/src/cli/cli-commands/coder/ping.ts +94 -0
  81. package/src/cli/cli-commands/coder/run.ts +25 -2
  82. package/src/cli/cli-commands/coder.ts +4 -0
  83. package/src/other/templates/getTemplatesPipelineCollection.ts +805 -842
  84. package/src/utils/agent-message-runtime/resolveAgentMessageRuntimeActivity.ts +101 -0
  85. package/src/version.ts +1 -1
  86. package/src/versions.txt +1 -1
  87. package/umd/index.umd.js +525 -171
  88. package/umd/index.umd.js.map +1 -1
  89. package/umd/scripts/run-agent-chat/runCoderPing.d.ts +48 -0
  90. package/umd/scripts/run-codex-prompts/prompts/findNextTodoPrompt.d.ts +2 -1
  91. package/umd/scripts/run-codex-prompts/prompts/isPromptCompatibleWithRunner.d.ts +27 -0
  92. package/umd/scripts/run-codex-prompts/prompts/listRunnablePrompts.d.ts +2 -1
  93. package/umd/scripts/run-codex-prompts/prompts/listUpcomingTasks.d.ts +2 -1
  94. package/umd/scripts/run-codex-prompts/prompts/replacePromptTodoStatusLine.d.ts +7 -0
  95. package/umd/scripts/run-codex-prompts/testing/TestBeforeMode.d.ts +16 -0
  96. package/umd/scripts/run-codex-prompts/testing/createTestBeforeRepairPrompt.d.ts +9 -0
  97. package/umd/scripts/run-codex-prompts/testing/limitTestOutput.d.ts +4 -0
  98. package/umd/scripts/run-codex-prompts/testing/runPromptTestCommand.d.ts +1 -2
  99. package/umd/scripts/run-codex-prompts/testing/runTestBefore.d.ts +24 -0
  100. package/umd/scripts/run-codex-prompts/ui/buildRunUiFrameShared.d.ts +1 -0
  101. package/umd/src/book-2.0/book-language-documentation/BookLanguageManualDictionary.d.ts +1 -15
  102. package/umd/src/book-2.0/book-language-documentation/getBookLanguageManualCommitmentGroups.d.ts +1 -1
  103. package/umd/src/book-2.0/book-language-documentation/renderCommitmentCatalogSection.d.ts +0 -4
  104. package/umd/src/book-components/Chat/utils/renderMarkdown.d.ts +7 -0
  105. package/umd/src/cli/cli-commands/coder/agentCodingFile.d.ts +2 -3
  106. package/umd/src/cli/cli-commands/coder/ping.d.ts +13 -0
  107. package/umd/src/cli/cli-commands/coder/ping.test.d.ts +1 -0
  108. package/umd/src/cli/cli-commands/coder.d.ts +1 -0
  109. package/apps/agents-server/src/app/api/onboarding/draft/route.ts +0 -23
  110. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/BookLanguagePanel.tsx +0 -125
  111. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownBookEditor.tsx +0 -154
  112. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/components/MarkdownPreview.tsx +0 -188
  113. package/apps/agents-server/src/components/NewAgentDialog/ManGoNewAgentWizard/services/draftService.ts +0 -32
@@ -1,7 +1,12 @@
1
1
  import { spaceTrim } from 'spacetrim';
2
+ import { parseAgentSourceWithCommitments } from '../agent-source/parseAgentSourceWithCommitments';
3
+ import type { string_book } from '../agent-source/string_book';
4
+ import type { BookCommitment } from '../../commitments/_base/BookCommitment';
5
+ import { getAllCommitmentTypes } from '../../commitments/_common/getAllCommitmentTypes';
2
6
  import { getCommitmentDefinition } from '../../commitments/_common/getCommitmentDefinition';
3
7
  import type { string_markdown } from '../../types/string_markdown';
4
8
  import { shiftMarkdownHeadingLevels } from '../../utils/markdown/shiftMarkdownHeadingLevels';
9
+ import { getSafeCodeBlock } from './getSafeCodeBlock';
5
10
 
6
11
  /**
7
12
  * Minimal commitment shape used by documentation renderers.
@@ -59,6 +64,23 @@ const CLOSED_COMMITMENT_TYPE = 'CLOSED';
59
64
  */
60
65
  const COMMITMENT_DOCUMENTATION_SECTION_HEADING_LEVEL = 2;
61
66
 
67
+ /**
68
+ * Markdown code blocks whose Book source is shown as a commitment example.
69
+ *
70
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
71
+ */
72
+ const BOOK_CODE_BLOCK_PATTERN = /(`{3,})book[^\n]*\n([\s\S]*?)\n\1/gu;
73
+
74
+ /**
75
+ * Recognized commitment types, ordered so compound keywords take priority over
76
+ * their shorter prefixes when reducing an example line by line.
77
+ *
78
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
79
+ */
80
+ const COMMITMENT_TYPES_BY_LENGTH = [...getAllCommitmentTypes()].sort(
81
+ (firstType, secondType) => secondType.length - firstType.length,
82
+ );
83
+
62
84
  /**
63
85
  * Removes the top-level heading from one commitment documentation block.
64
86
  *
@@ -76,12 +98,18 @@ function removeLeadingTopLevelHeading(markdown: string): string {
76
98
  *
77
99
  * @param title - Heading label for the subsection.
78
100
  * @param documentation - Raw commitment documentation markdown.
101
+ * @param group - Commitment family represented by the documentation entry.
79
102
  * @param headingLevelShift - How many levels the whole entry is nested by its host document.
80
103
  * @returns Markdown subsection introducing one commitment of the family.
81
104
  *
82
105
  * @private internal utility of `createStandaloneBookLanguageMarkdown`
83
106
  */
84
- function renderDocumentationSection(title: string, documentation: string, headingLevelShift: number): string {
107
+ function renderDocumentationSection(
108
+ title: string,
109
+ documentation: string,
110
+ group: GroupedCommitmentDocumentationSource,
111
+ headingLevelShift: number,
112
+ ): string {
85
113
  const headingPrefix = '#'.repeat(COMMITMENT_DOCUMENTATION_SECTION_HEADING_LEVEL + headingLevelShift);
86
114
 
87
115
  return spaceTrim(
@@ -90,7 +118,9 @@ function renderDocumentationSection(title: string, documentation: string, headin
90
118
 
91
119
  ${block(
92
120
  shiftMarkdownHeadingLevels(
93
- removeLeadingTopLevelHeading(documentation) as string_markdown,
121
+ removeLeadingTopLevelHeading(
122
+ renderFocusedCommitmentExamples(documentation, group),
123
+ ) as string_markdown,
94
124
  headingLevelShift + 1,
95
125
  ),
96
126
  )}
@@ -116,7 +146,10 @@ export function renderGroupedCommitmentDocumentationMarkdown(
116
146
  ): string {
117
147
  const commitmentTypes = new Set([group.primary.type, ...group.aliases]);
118
148
 
119
- if (commitmentTypes.has(OPEN_COMMITMENT_TYPE) && commitmentTypes.has(CLOSED_COMMITMENT_TYPE)) {
149
+ const isOpenClosedCommitmentFamily =
150
+ commitmentTypes.has(OPEN_COMMITMENT_TYPE) && commitmentTypes.has(CLOSED_COMMITMENT_TYPE);
151
+
152
+ if (isOpenClosedCommitmentFamily) {
120
153
  const openCommitmentDefinition = getCommitmentDefinition(OPEN_COMMITMENT_TYPE);
121
154
  const closedCommitmentDefinition = getCommitmentDefinition(CLOSED_COMMITMENT_TYPE);
122
155
 
@@ -127,6 +160,7 @@ export function renderGroupedCommitmentDocumentationMarkdown(
127
160
  renderDocumentationSection(
128
161
  OPEN_COMMITMENT_TYPE,
129
162
  openCommitmentDefinition.documentation,
163
+ group,
130
164
  headingLevelShift,
131
165
  ),
132
166
  )}
@@ -135,6 +169,7 @@ export function renderGroupedCommitmentDocumentationMarkdown(
135
169
  renderDocumentationSection(
136
170
  CLOSED_COMMITMENT_TYPE,
137
171
  closedCommitmentDefinition.documentation,
172
+ group,
138
173
  headingLevelShift,
139
174
  ),
140
175
  )}
@@ -144,7 +179,259 @@ export function renderGroupedCommitmentDocumentationMarkdown(
144
179
  }
145
180
 
146
181
  return shiftMarkdownHeadingLevels(
147
- removeLeadingTopLevelHeading(group.primary.documentation) as string_markdown,
182
+ removeLeadingTopLevelHeading(
183
+ renderFocusedCommitmentExamples(group.primary.documentation, group),
184
+ ) as string_markdown,
148
185
  headingLevelShift,
149
186
  );
150
187
  }
188
+
189
+ /**
190
+ * Rewrites Book examples in commitment documentation to show one canonical
191
+ * commitment in isolation, with only `GOAL` and `CLOSED` as supporting syntax.
192
+ *
193
+ * @param documentation - Raw commitment documentation markdown.
194
+ * @param group - Commitment family represented by the documentation entry.
195
+ * @returns Documentation whose Book examples use focused canonical syntax.
196
+ *
197
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
198
+ */
199
+ function renderFocusedCommitmentExamples(
200
+ documentation: string,
201
+ group: GroupedCommitmentDocumentationSource,
202
+ ): string {
203
+ return documentation.replace(BOOK_CODE_BLOCK_PATTERN, (codeBlock, _fence, source: string) => {
204
+ const focusedSource = createFocusedCommitmentExampleSource(source, group);
205
+ return focusedSource ? getSafeCodeBlock(focusedSource, 'book') : codeBlock;
206
+ });
207
+ }
208
+
209
+ /**
210
+ * Creates a focused Book source example for one commitment documentation entry.
211
+ *
212
+ * @param source - Original Book source from the commitment documentation.
213
+ * @param group - Commitment family represented by the documentation entry.
214
+ * @returns Focused source, or `null` when the source cannot be safely reduced.
215
+ *
216
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
217
+ */
218
+ function createFocusedCommitmentExampleSource(
219
+ source: string,
220
+ group: GroupedCommitmentDocumentationSource,
221
+ ): string | null {
222
+ const parsedSource = parseAgentSourceWithCommitments(source as string_book);
223
+ const commitmentTypes = new Set([group.primary.type, ...group.aliases]);
224
+ const isOpenClosedCommitmentFamily =
225
+ commitmentTypes.has(OPEN_COMMITMENT_TYPE) && commitmentTypes.has(CLOSED_COMMITMENT_TYPE);
226
+ const allowedCommitmentTypes = new Set([
227
+ group.primary.type,
228
+ ...group.aliases,
229
+ 'GOAL',
230
+ CLOSED_COMMITMENT_TYPE,
231
+ ]);
232
+ const canonicalTypeByCommitmentType = createCanonicalCommitmentTypeByCommitmentType(
233
+ group,
234
+ isOpenClosedCommitmentFamily,
235
+ );
236
+ const focusedCommitments = parsedSource.commitments
237
+ .filter((commitment) => allowedCommitmentTypes.has(commitment.type))
238
+ .map((commitment) => {
239
+ const type = canonicalTypeByCommitmentType.get(commitment.type) || commitment.type;
240
+ return `${type}${commitment.content ? ` ${commitment.content}` : ''}`;
241
+ });
242
+
243
+ if (focusedCommitments.length > 0) {
244
+ return finalizeFocusedCommitmentExampleSource(
245
+ getFocusedExampleAgentName(parsedSource.agentName),
246
+ focusedCommitments,
247
+ );
248
+ }
249
+
250
+ return createLineFocusedCommitmentExampleSource(source, group, isOpenClosedCommitmentFamily);
251
+ }
252
+
253
+ /**
254
+ * Creates a focused example when the Book parser cannot recognize the target
255
+ * commitment because it appears as the first source line or has a shared prefix.
256
+ *
257
+ * @param source - Original Book source from the documentation code block.
258
+ * @param group - Commitment family represented by the documentation entry.
259
+ * @param isOpenClosedCommitmentFamily - Whether the family contains both switch commitments.
260
+ * @returns Focused source, or `null` when the source does not use this commitment family.
261
+ *
262
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
263
+ */
264
+ function createLineFocusedCommitmentExampleSource(
265
+ source: string,
266
+ group: GroupedCommitmentDocumentationSource,
267
+ isOpenClosedCommitmentFamily: boolean,
268
+ ): string | null {
269
+ const sourceLines = source.split(/\r?\n/u);
270
+ const allowedCommitmentTypes = new Set([group.primary.type, ...group.aliases, 'GOAL', CLOSED_COMMITMENT_TYPE]);
271
+ const canonicalTypeByCommitmentType = createCanonicalCommitmentTypeByCommitmentType(
272
+ group,
273
+ isOpenClosedCommitmentFamily,
274
+ );
275
+ const focusedCommitments: Array<string> = [];
276
+ const firstSourceLine = sourceLines.find((line) => line.trim().length > 0) || null;
277
+ const firstCommitmentType = firstSourceLine ? getCommitmentTypeAtLine(firstSourceLine) : null;
278
+ const agentName = firstSourceLine && !firstCommitmentType ? firstSourceLine.trim() : null;
279
+ let activeFocusedCommitmentIndex: number | null = null;
280
+ let isInsideCodeBlock = false;
281
+
282
+ for (const sourceLine of sourceLines) {
283
+ const trimmedSourceLine = sourceLine.trim();
284
+
285
+ if (trimmedSourceLine.startsWith('```')) {
286
+ appendLineToActiveCommitment(focusedCommitments, activeFocusedCommitmentIndex, sourceLine);
287
+ isInsideCodeBlock = !isInsideCodeBlock;
288
+ continue;
289
+ }
290
+
291
+ if (isInsideCodeBlock) {
292
+ appendLineToActiveCommitment(focusedCommitments, activeFocusedCommitmentIndex, sourceLine);
293
+ continue;
294
+ }
295
+
296
+ const commitmentType = getCommitmentTypeAtLine(sourceLine);
297
+
298
+ if (!commitmentType) {
299
+ appendLineToActiveCommitment(focusedCommitments, activeFocusedCommitmentIndex, sourceLine);
300
+ continue;
301
+ }
302
+
303
+ if (!allowedCommitmentTypes.has(commitmentType)) {
304
+ activeFocusedCommitmentIndex = null;
305
+ continue;
306
+ }
307
+
308
+ const canonicalType = canonicalTypeByCommitmentType.get(commitmentType) || commitmentType;
309
+ const content = trimmedSourceLine.slice(commitmentType.length).trimStart();
310
+ focusedCommitments.push(`${canonicalType}${content ? ` ${content}` : ''}`);
311
+ activeFocusedCommitmentIndex = focusedCommitments.length - 1;
312
+ }
313
+
314
+ return finalizeFocusedCommitmentExampleSource(agentName, focusedCommitments);
315
+ }
316
+
317
+ /**
318
+ * Finds the longest supported commitment keyword at the start of a source line.
319
+ *
320
+ * @param sourceLine - One Book source line to inspect.
321
+ * @returns Matching commitment type, or `null` when the line is ordinary content.
322
+ *
323
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
324
+ */
325
+ function getCommitmentTypeAtLine(sourceLine: string): BookCommitment | null {
326
+ const trimmedSourceLine = sourceLine.trim();
327
+
328
+ return (
329
+ COMMITMENT_TYPES_BY_LENGTH.find(
330
+ (commitmentType) =>
331
+ trimmedSourceLine === commitmentType || trimmedSourceLine.startsWith(`${commitmentType} `),
332
+ ) || null
333
+ );
334
+ }
335
+
336
+ /**
337
+ * Appends a source line only when a focused commitment currently owns it.
338
+ *
339
+ * @param focusedCommitments - Focused commitments assembled from the example.
340
+ * @param activeFocusedCommitmentIndex - Index of the commitment receiving continuation lines.
341
+ * @param sourceLine - Source line to append.
342
+ *
343
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
344
+ */
345
+ function appendLineToActiveCommitment(
346
+ focusedCommitments: Array<string>,
347
+ activeFocusedCommitmentIndex: number | null,
348
+ sourceLine: string,
349
+ ): void {
350
+ if (activeFocusedCommitmentIndex === null) {
351
+ return;
352
+ }
353
+
354
+ focusedCommitments[activeFocusedCommitmentIndex] += `\n${sourceLine}`;
355
+ }
356
+
357
+ /**
358
+ * Adds the standard closing marker and formats one reduced Book example.
359
+ *
360
+ * @param agentName - Optional human-readable title retained from the original example.
361
+ * @param focusedCommitments - Canonical commitment blocks kept in the example.
362
+ * @returns Focused source, or `null` when no relevant commitment was found.
363
+ *
364
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
365
+ */
366
+ function finalizeFocusedCommitmentExampleSource(
367
+ agentName: string | null,
368
+ focusedCommitments: Array<string>,
369
+ ): string | null {
370
+ const normalizedFocusedCommitments = focusedCommitments.map((commitment) => commitment.trim());
371
+
372
+ if (normalizedFocusedCommitments.length === 0) {
373
+ return null;
374
+ }
375
+
376
+ const isClosedCommitmentIncluded = normalizedFocusedCommitments.some((commitment) =>
377
+ commitment.startsWith(CLOSED_COMMITMENT_TYPE),
378
+ );
379
+ const isOpenCommitmentIncluded = normalizedFocusedCommitments.some((commitment) =>
380
+ commitment.startsWith(OPEN_COMMITMENT_TYPE),
381
+ );
382
+
383
+ if (!isClosedCommitmentIncluded && !isOpenCommitmentIncluded) {
384
+ normalizedFocusedCommitments.push(CLOSED_COMMITMENT_TYPE);
385
+ }
386
+
387
+ return [agentName, ...normalizedFocusedCommitments]
388
+ .filter((line): line is string => Boolean(line))
389
+ .join('\n\n');
390
+ }
391
+
392
+ /**
393
+ * Keeps an example title unless the parser interpreted a commitment-only
394
+ * example's first line as its mandatory agent name.
395
+ *
396
+ * @param agentName - Parsed agent name from the original example.
397
+ * @returns Agent title suitable for a focused example, or `null` when absent.
398
+ *
399
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
400
+ */
401
+ function getFocusedExampleAgentName(agentName: string | null): string | null {
402
+ if (!agentName || getCommitmentDefinition(agentName as BookCommitment)) {
403
+ return null;
404
+ }
405
+
406
+ return agentName;
407
+ }
408
+
409
+ /**
410
+ * Maps aliases to the canonical keyword shown by a commitment example.
411
+ *
412
+ * `OPEN` and `CLOSED` share one documentation entry, but each remains a
413
+ * distinct keyword and must therefore retain its own spelling.
414
+ *
415
+ * @param group - Commitment family represented by the documentation entry.
416
+ * @param isOpenClosedCommitmentFamily - Whether the family contains both switch commitments.
417
+ * @returns Canonical keyword by accepted source keyword.
418
+ *
419
+ * @private internal utility of `createStandaloneBookLanguageMarkdown`
420
+ */
421
+ function createCanonicalCommitmentTypeByCommitmentType(
422
+ group: GroupedCommitmentDocumentationSource,
423
+ isOpenClosedCommitmentFamily: boolean,
424
+ ): ReadonlyMap<string, string> {
425
+ const canonicalTypeByCommitmentType = new Map<string, string>();
426
+
427
+ canonicalTypeByCommitmentType.set(group.primary.type, group.primary.type);
428
+
429
+ for (const alias of group.aliases) {
430
+ canonicalTypeByCommitmentType.set(
431
+ alias,
432
+ isOpenClosedCommitmentFamily ? alias : group.primary.type,
433
+ );
434
+ }
435
+
436
+ return canonicalTypeByCommitmentType;
437
+ }
@@ -272,6 +272,16 @@ const DETAILS_PLACEHOLDER_WRAPPED_REGEX = new RegExp(`<p>\\s*(${DETAILS_PLACEHOL
272
272
  */
273
273
  const INLINE_REFERENCE_REGEX = /\[\[([^\]\r\n]+?)\]\]/g;
274
274
 
275
+ /**
276
+ * Pattern matching ordinary markdown links that can be promoted to inline reference chips.
277
+ *
278
+ * Images are intentionally captured separately and left unchanged by the replacement helper.
279
+ *
280
+ * @private utility of `renderMarkdown`
281
+ */
282
+ const MARKDOWN_INLINE_REFERENCE_LINK_REGEX =
283
+ /(!?)\[([^\]\r\n]*)\]\(\s*(<[^>\r\n]+>|[^)\s]+)(?:\s+(?:"[^"\r\n]*"|'[^'\r\n]*'|\([^)]*\)))?\s*\)/g;
284
+
275
285
  /**
276
286
  * Markdown patterns that are strong enough to identify content as markdown.
277
287
  */
@@ -339,6 +349,14 @@ export type MarkdownInlineReference = {
339
349
  */
340
350
  readonly href: string;
341
351
 
352
+ /**
353
+ * Markdown link destination prefixes that should render as this reference as well.
354
+ *
355
+ * This supports legacy links such as an Agents Server project file URL while keeping
356
+ * `reference` as the canonical `[[project]]` token.
357
+ */
358
+ readonly sourceHrefPrefixes?: ReadonlyArray<string>;
359
+
342
360
  /**
343
361
  * Optional hover title for the rendered reference.
344
362
  */
@@ -699,11 +717,12 @@ const CHAT_MARKDOWN_CONVERTER = createChatMarkdownConverter();
699
717
  * outer `<details>` and optional `<summary>` markup untouched.
700
718
  *
701
719
  * @param detailsBlock - Raw `<details>...</details>` HTML captured from markdown.
720
+ * @param options - Markdown rendering options to reuse for the details body.
702
721
  * @returns `<details>` HTML whose body has been converted from markdown to HTML.
703
722
  *
704
723
  * @private utility of `renderMarkdown`
705
724
  */
706
- function renderDetailsBlock(detailsBlock: string): string_html {
725
+ function renderDetailsBlock(detailsBlock: string, options?: RenderMarkdownOptions): string_html {
707
726
  const openTagMatch = detailsBlock.match(/^<details\b[^>]*>/i);
708
727
  const closeTagMatch = detailsBlock.match(/<\/details\s*>$/i);
709
728
 
@@ -717,7 +736,7 @@ function renderDetailsBlock(detailsBlock: string): string_html {
717
736
  const summaryMatch = innerContent.match(/^(\s*<summary\b[^>]*>[\s\S]*?<\/summary\s*>)([\s\S]*)$/i);
718
737
  const summaryHtml = summaryMatch?.[1] ?? '';
719
738
  const bodyMarkdown = (summaryMatch?.[2] ?? innerContent) as string_markdown;
720
- const renderedBody = renderMarkdown(bodyMarkdown);
739
+ const renderedBody = renderMarkdown(bodyMarkdown, options);
721
740
 
722
741
  return `${openTag}${summaryHtml}${renderedBody}${closeTag}` as string_html;
723
742
  }
@@ -761,17 +780,18 @@ function maskMarkdownCodeSegments(markdown: string_markdown): MaskedCodeSegments
761
780
  * processes their content.
762
781
  *
763
782
  * @param markdown - Markdown text that may contain raw HTML `<details>` blocks.
783
+ * @param options - Markdown rendering options to reuse for the details body.
764
784
  * @returns Masked markdown and a restore helper that returns `string_html`.
765
785
  *
766
786
  * @private utility of `renderMarkdown`
767
787
  */
768
- function maskDetailsBlocks(markdown: string_markdown): MaskedDetailsBlocksResult {
788
+ function maskDetailsBlocks(markdown: string_markdown, options?: RenderMarkdownOptions): MaskedDetailsBlocksResult {
769
789
  const blocks: string_html[] = [];
770
790
 
771
791
  DETAILS_BLOCK_REGEX.lastIndex = 0;
772
792
  const masked = markdown.replace(DETAILS_BLOCK_REGEX, (match) => {
773
793
  const placeholder = `${DETAILS_PLACEHOLDER_PREFIX}${blocks.length}__`;
774
- blocks.push(renderDetailsBlock(match));
794
+ blocks.push(renderDetailsBlock(match, options));
775
795
  return placeholder;
776
796
  }) as string_markdown;
777
797
 
@@ -885,6 +905,93 @@ function createMarkdownInlineReferenceByKey(
885
905
  return referenceByKey;
886
906
  }
887
907
 
908
+ /**
909
+ * Returns whether a href starts with a configured source href prefix.
910
+ *
911
+ * @param href - Markdown link destination.
912
+ * @param sourceHrefPrefix - Configured source href prefix.
913
+ * @returns Whether the href belongs to the source prefix.
914
+ *
915
+ * @private utility of `renderMarkdown`
916
+ */
917
+ function doesHrefStartWithSourceHrefPrefix(href: string, sourceHrefPrefix: string): boolean {
918
+ if (href === sourceHrefPrefix) {
919
+ return true;
920
+ }
921
+
922
+ const normalizedSourceHrefPrefix = sourceHrefPrefix.endsWith('/') ? sourceHrefPrefix : `${sourceHrefPrefix}/`;
923
+
924
+ return href.startsWith(normalizedSourceHrefPrefix);
925
+ }
926
+
927
+ /**
928
+ * Returns a comparable path for an absolute href when the configured source prefix is relative.
929
+ *
930
+ * @param href - Href to normalize.
931
+ * @returns Absolute URL pathname or the original href when it is relative/invalid.
932
+ *
933
+ * @private utility of `renderMarkdown`
934
+ */
935
+ function resolveAbsoluteHrefPath(href: string): string {
936
+ try {
937
+ return new URL(href).pathname;
938
+ } catch {
939
+ return href;
940
+ }
941
+ }
942
+
943
+ /**
944
+ * Returns whether one markdown link destination belongs to one inline reference.
945
+ *
946
+ * Relative project paths also match absolute URLs on the current server, which keeps
947
+ * server-generated relative links and model-generated absolute links consistent.
948
+ *
949
+ * @param reference - Candidate inline reference.
950
+ * @param href - Markdown link destination.
951
+ * @returns Whether the href should render as the reference chip.
952
+ *
953
+ * @private utility of `renderMarkdown`
954
+ */
955
+ function doesMarkdownInlineReferenceMatchHref(reference: MarkdownInlineReference, href: string): boolean {
956
+ const normalizedHref = href.trim();
957
+
958
+ return (reference.sourceHrefPrefixes || []).some((sourceHrefPrefix) => {
959
+ const normalizedSourceHrefPrefix = sourceHrefPrefix.trim();
960
+ if (!normalizedSourceHrefPrefix) {
961
+ return false;
962
+ }
963
+
964
+ if (doesHrefStartWithSourceHrefPrefix(normalizedHref, normalizedSourceHrefPrefix)) {
965
+ return true;
966
+ }
967
+
968
+ const isRelativeSourceHrefPrefix = !/^[a-z][a-z0-9+.-]*:/i.test(normalizedSourceHrefPrefix);
969
+ const isAbsoluteHref = /^[a-z][a-z0-9+.-]*:/i.test(normalizedHref);
970
+
971
+ return (
972
+ isRelativeSourceHrefPrefix &&
973
+ isAbsoluteHref &&
974
+ doesHrefStartWithSourceHrefPrefix(resolveAbsoluteHrefPath(normalizedHref), normalizedSourceHrefPrefix)
975
+ );
976
+ });
977
+ }
978
+
979
+ /**
980
+ * Finds the inline reference represented by a markdown link destination.
981
+ *
982
+ * @param references - Inline references available to the markdown renderer.
983
+ * @param href - Markdown link destination.
984
+ * @returns Matching reference or `undefined` when the href is unrelated.
985
+ *
986
+ * @private utility of `renderMarkdown`
987
+ */
988
+ function findMarkdownInlineReferenceByHref(
989
+ references: ReadonlyArray<MarkdownInlineReference>,
990
+ href: string,
991
+ ): MarkdownInlineReference | undefined {
992
+ return references.find((reference) => doesMarkdownInlineReferenceMatchHref(reference, href));
993
+ }
994
+
888
995
  /**
889
996
  * Renders one inline reference as raw HTML that is sanitized by the shared markdown sanitizer.
890
997
  *
@@ -977,11 +1084,28 @@ function applyMarkdownInlineReferences(markdown: string_markdown, options?: Rend
977
1084
  return markdown;
978
1085
  }
979
1086
 
980
- return markdown.replace(INLINE_REFERENCE_REGEX, (match, rawReference: string) => {
981
- const reference = referenceByKey.get(normalizeMarkdownInlineReferenceKey(rawReference));
1087
+ const markdownWithInlineReferenceTokens = markdown.replace(
1088
+ INLINE_REFERENCE_REGEX,
1089
+ (match, rawReference: string) => {
1090
+ const reference = referenceByKey.get(normalizeMarkdownInlineReferenceKey(rawReference));
982
1091
 
983
- return reference ? renderMarkdownInlineReferenceHtml(reference, className) : match;
984
- }) as string_markdown;
1092
+ return reference ? renderMarkdownInlineReferenceHtml(reference, className) : match;
1093
+ },
1094
+ );
1095
+
1096
+ return markdownWithInlineReferenceTokens.replace(
1097
+ MARKDOWN_INLINE_REFERENCE_LINK_REGEX,
1098
+ (match, imageMarker: string, _linkLabel: string, rawHref: string) => {
1099
+ if (imageMarker) {
1100
+ return match;
1101
+ }
1102
+
1103
+ const href = rawHref.replace(/^<|>$/g, '');
1104
+ const reference = findMarkdownInlineReferenceByHref(references, href);
1105
+
1106
+ return reference ? renderMarkdownInlineReferenceHtml(reference, className) : match;
1107
+ },
1108
+ ) as string_markdown;
985
1109
  }
986
1110
 
987
1111
  /**
@@ -1026,7 +1150,7 @@ export function renderMarkdown(markdown: string_markdown, options?: RenderMarkdo
1026
1150
 
1027
1151
  try {
1028
1152
  const normalizedMarkdown = normalizeMarkdownSublists(markdown);
1029
- const { masked: maskedMarkdown, restore: restoreDetails } = maskDetailsBlocks(normalizedMarkdown);
1153
+ const { masked: maskedMarkdown, restore: restoreDetails } = maskDetailsBlocks(normalizedMarkdown, options);
1030
1154
  const { masked: codeMaskedMarkdown, restore: restoreCode } = maskMarkdownCodeSegments(maskedMarkdown);
1031
1155
  const referencedMarkdown = applyMarkdownInlineReferences(codeMaskedMarkdown, options);
1032
1156
  const inlineReferenceMarkdown = restoreCode(referencedMarkdown);
@@ -25,5 +25,6 @@ export function createLocalAgentRunOptions(
25
25
  autoClone: false,
26
26
  maxMessageProcessingFailures: localAgentRunnerLimits.maxFailedAttempts,
27
27
  maxParallelMessages: localAgentRunnerLimits.maxParallelMessages,
28
+ isMachineReadableProgressEnabled: true,
28
29
  };
29
30
  }